Skip to content

Commit 04b371f

Browse files
committed
typechecker+interpreter: Expose comptime generics as comptime variables
...unless they're of a trivial type which C++ can safely have as an NTTP.
1 parent d8be1ed commit 04b371f

9 files changed

Lines changed: 71 additions & 44 deletions
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
/// Expect:
22
/// - output: "70\n"
33

4-
comptime id<T>(anon x: T) -> T => x
5-
64
fn actually_kinda_useless<comptime T>() -> i32 {
7-
// FIXME: Can't really acccess the value of 'T' outside a comptime context yet (a binding exists, but not at runtime)
8-
return id(T) as! i32 + 1
5+
return T + 1
96
}
107

118
fn main() {
12-
println("{}", actually_kinda_useless<comptime 69>())
9+
println("{}", actually_kinda_useless<comptime 69i32>())
1310
}
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
/// Expect:
22
/// - output: "typed: 10\nuntyped: 20\n"
33

4-
comptime id<T>(anon x: T) -> T => x
5-
64
fn typed_version<comptime N: i32>() -> i32 {
7-
return id(N) as! i32
5+
return N
86
}
97

108
fn untyped_version<comptime N>() -> i32 {
11-
return id(N) as! i32
9+
return N
1210
}
1311

1412
fn main() {
1513
println("typed: {}", typed_version<comptime 10i32>())
16-
println("untyped: {}", untyped_version<comptime 20>())
14+
println("untyped: {}", untyped_version<comptime 20i32>())
1715
}

samples/generics/typed_const_generic_bool.jakt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
/// Expect:
22
/// - output: "true\nfalse\n"
33

4-
comptime id<T>(anon x: T) -> T => x
5-
64
fn is_enabled<comptime B: bool>() -> bool {
7-
return id(B) as! bool
5+
return B
86
}
97

108
fn main() {

samples/generics/typed_const_generic_i32.jakt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
/// Expect:
22
/// - output: "42\n"
33

4-
comptime id<T>(anon x: T) -> T => x
5-
64
fn get_value<comptime N: i32>() -> i32 {
7-
return id(N) as! i32
5+
return N
86
}
97

108
fn main() {

samples/generics/typed_const_generic_multiple.jakt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
comptime id<T>(anon x: T) -> T => x
55

66
fn multiply<comptime A: i32, comptime B: i32>() -> i32 {
7-
let a = id(A) as! i32
8-
let b = id(B) as! i32
9-
return a * b
7+
return A * B
108
}
119

1210
fn main() {

samples/generics/typed_const_generic_u64.jakt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
comptime id<T>(anon x: T) -> T => x
55

66
fn add_ten<comptime N: u64>() -> u64 {
7-
return (id(N) as! u64) + 10u64
7+
return N + 10u64
88
}
99

1010
fn main() {

samples/generics/typed_const_generic_with_type_param.jakt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33

44
comptime id<T>(anon x: T) -> T => x
55

6-
fn format_with_count<T, comptime N: i32>(anon value: T) throws -> String {
7-
let count = id(N) as! i32
6+
fn format_with_count<comptime N: i32, comptime value: String>() throws -> String {
7+
let count = N
88
return format("{} {}", value, count)
99
}
1010

1111
fn main() {
12-
println("{}", format_with_count<String, comptime 5i32>("hello"))
12+
println("{}", format_with_count<comptime 5i32, comptime "hello">())
1313
}

selfhost/interpreter.jakt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3545,13 +3545,32 @@ class Interpreter {
35453545
}
35463546
}
35473547

3548+
// Add comptime generic parameter values as interpreter bindings
3549+
mut comptime_bindings: [String:Value] = [:]
3550+
for i in 0..function_to_run.generics.params.size() {
3551+
let param = function_to_run.generics.params[i]
3552+
let param_type_id = param.checked_parameter.type_id
3553+
if .program.get_type(param_type_id) is TypeVariable(name, is_value) and is_value {
3554+
if i < function_to_run.generics.specializations.size() and function_to_run.specialization_index.has_value() {
3555+
let spec = function_to_run.generics.specializations[function_to_run.specialization_index!]
3556+
if i < spec.size() and .program.get_type(spec[i]) is Const(value) {
3557+
comptime_bindings[name] = value
3558+
}
3559+
}
3560+
}
3561+
}
3562+
35483563
match function_to_run.type {
35493564
Normal => {
35503565
mut scope = InterpreterScope::create(parent: invocation_scope, compiler: .compiler, runtime_scope_id)
35513566
defer {
35523567
scope.perform_defers(interpreter: this, span: call_span)
35533568
}
35543569

3570+
for pair in comptime_bindings {
3571+
scope.bindings[pair.0] = pair.1
3572+
}
3573+
35553574
for i in 0..function_to_run.params.size() {
35563575
if this_offset != 0 and i == 0 {
35573576
continue
@@ -3580,6 +3599,10 @@ class Interpreter {
35803599
scope.perform_defers(interpreter: this, span: call_span)
35813600
}
35823601

3602+
for pair in comptime_bindings {
3603+
scope.bindings[pair.0] = pair.1
3604+
}
3605+
35833606
for i in 0..function_to_run.params.size() {
35843607
if this_offset != 0 and i == 0 {
35853608
continue

selfhost/typechecker.jakt

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4890,16 +4890,6 @@ struct Typechecker {
48904890
}
48914891
}
48924892
scope.comptime_bindings[type_name] = value
4893-
let checked_var = CheckedVariable(
4894-
name: type_name
4895-
type_id: value.impl.type_id(&mut .program)
4896-
is_mutable: false
4897-
definition_span: value.span
4898-
type_span: None
4899-
visibility: CheckedVisibility::Public
4900-
invisible_to_ide: false
4901-
)
4902-
scope.vars[type_name] = module.add_variable(checked_var)
49034893
}
49044894

49054895
if dependent_scope_id.has_value() {
@@ -9245,13 +9235,44 @@ struct Typechecker {
92459235

92469236
yield CheckedExpression::OptionalSome(expr: checked_expr, span, type_id: optional_type_id)
92479237
}
9248-
Var(name, span) => {
9249-
let var = .find_var_in_scope(scope_id, var: name)
9250-
let result = match var {
9251-
Some(var_) => CheckedExpression::Var(var: var_, span)
9238+
Var(name, span) => match .find_var_in_scope(scope_id, var: name) {
9239+
Some(var) => {
9240+
let var = .find_var_in_scope(scope_id, var: name)
9241+
let result = match var {
9242+
Some(var_) => CheckedExpression::Var(var: var_, span)
9243+
None => {
9244+
.error(format("Variable '{}' not found", name), span)
9245+
9246+
mut type_id: TypeId? = None
9247+
if type_hint.has_value() {
9248+
type_id = type_hint!.type_id
9249+
}
9250+
9251+
yield CheckedExpression::Var(
9252+
var: CheckedVariable(
9253+
name,
9254+
type_id: type_id.value_or(unknown_type_id()),
9255+
is_mutable: false,
9256+
definition_span: span,
9257+
type_span: None
9258+
visibility: CheckedVisibility::Public
9259+
invisible_to_ide: false
9260+
),
9261+
span
9262+
)
9263+
}
9264+
}
9265+
9266+
if type_hint is Some(hint) and hint is MustBe(type_id) {
9267+
.unify_with_type(found_type: result.type(), expected_type: type_id, span)
9268+
}
9269+
9270+
yield result
9271+
}
9272+
None => match .find_comptime_binding_in_scope(scope_id, name) {
9273+
Some(value) => value_to_checked_expression(value, interpreter: .interpreter())
92529274
None => {
92539275
.error(format("Variable '{}' not found", name), span)
9254-
92559276
mut type_id: TypeId? = None
92569277
if type_hint.has_value() {
92579278
type_id = type_hint!.type_id
@@ -9271,12 +9292,6 @@ struct Typechecker {
92719292
)
92729293
}
92739294
}
9274-
9275-
if type_hint is Some(hint) and hint is MustBe(type_id) {
9276-
.unify_with_type(found_type: result.type(), expected_type: type_id, span)
9277-
}
9278-
9279-
yield result
92809295
}
92819296
ForcedUnwrap(expr, span) => {
92829297
let checked_expr = .typecheck_expression_and_dereference_if_needed(expr, scope_id, safety_mode, type_hint: None, span)

0 commit comments

Comments
 (0)