Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/check/Check.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5794,8 +5794,11 @@ fn checkExpr(self: *Self, expr_idx: CIR.Expr.Idx, env: *Env, expected: Expected)
const expr_var_raw = ModuleEnv.varFrom(expr_idx);

// Consume the checking_call_arg flag: it applies only to this immediate
// checkExpr call and must not propagate to recursive calls (e.g. e_closure
// delegating to its inner e_lambda, or nested call arguments).
// checkExpr call and must not propagate to recursive calls (e.g. nested call
// arguments). The one exception is `e_closure`, which is only the capture
// wrapper around its inner `e_lambda`: the lambda is the actual argument
// value, so the closure re-asserts this flag before delegating to it (see the
// `.e_closure` case) to keep an argument lambda from being generalized.
const is_call_arg = self.checking_call_arg;
self.checking_call_arg = false;

Expand Down Expand Up @@ -6815,7 +6818,13 @@ fn checkExpr(self: *Self, expr_idx: CIR.Expr.Idx, env: *Env, expected: Expected)
},
.e_closure => |closure| {
// Here, we must forward the expected valued to the inner lambda, so
// the annotation type is created at the same rank as the expr
// the annotation type is created at the same rank as the expr.
// A closure is only the capture wrapper around its inner lambda, so
// the lambda inherits this closure's call-arg status: an argument
// lambda must NOT be generalized, or its body's static-dispatch chain
// would be quantified before the caller pins the parameter types,
// leaving the original (un-instantiated) dispatch nodes unresolved.
self.checking_call_arg = is_call_arg;
does_fx = try self.checkExpr(closure.lambda_idx, env, expected) or does_fx;
const lambda_var = ModuleEnv.varFrom(closure.lambda_idx);

Expand Down
147 changes: 147 additions & 0 deletions test/snapshots/dispatch_on_quote_literal_through_find_first.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# META
~~~ini
description=Static dispatch chain on a find_first predicate's string-literal param resolves; the ?? default literal that previously orphaned the dispatch (when the capturing closure argument was prematurely generalized) no longer breaks it
type=snippet
~~~
# SOURCE
~~~roc
foo : U8 -> Str
foo = |letter| {
val = ["hello", "world"].find_first(|letters| letters.to_utf8().contains(letter)) ?? ""
val
}
~~~
# EXPECTED
NIL
# PROBLEMS
NIL
# TOKENS
~~~zig
LowerIdent,OpColon,UpperIdent,OpArrow,UpperIdent,
LowerIdent,OpAssign,OpBar,LowerIdent,OpBar,OpenCurly,
LowerIdent,OpAssign,OpenSquare,StringStart,StringPart,StringEnd,Comma,StringStart,StringPart,StringEnd,CloseSquare,NoSpaceDotLowerIdent,NoSpaceOpenRound,OpBar,LowerIdent,OpBar,LowerIdent,NoSpaceDotLowerIdent,NoSpaceOpenRound,CloseRound,NoSpaceDotLowerIdent,NoSpaceOpenRound,LowerIdent,CloseRound,CloseRound,OpDoubleQuestion,StringStart,StringPart,StringEnd,
LowerIdent,
CloseCurly,
EndOfFile,
~~~
# PARSE
~~~clojure
(file
(type-module)
(statements
(s-type-anno (name "foo")
(ty-fn
(ty (name "U8"))
(ty (name "Str"))))
(s-decl
(p-ident (raw "foo"))
(e-lambda
(args
(p-ident (raw "letter")))
(e-block
(statements
(s-decl
(p-ident (raw "val"))
(e-binop (op "??")
(e-method-call (method ".find_first")
(receiver
(e-list
(e-string
(e-string-part (raw "hello")))
(e-string
(e-string-part (raw "world")))))
(args
(e-lambda
(args
(p-ident (raw "letters")))
(e-method-call (method ".contains")
(receiver
(e-method-call (method ".to_utf8")
(receiver
(e-ident (raw "letters")))
(args)))
(args
(e-ident (raw "letter")))))))
(e-string
(e-string-part (raw "")))))
(e-ident (raw "val"))))))))
~~~
# FORMATTED
~~~roc
foo : U8 -> Str
foo = |letter| {
val = ["hello", "world"].find_first(|letters| letters.to_utf8().contains(letter)) ?? ""
val
}
~~~
# CANONICALIZE
~~~clojure
(can-ir
(d-let
(p-assign (ident "foo"))
(e-lambda
(args
(p-assign (ident "letter")))
(e-block
(s-let
(p-assign (ident "val"))
(e-match
(match
(cond
(e-dispatch-call (method "find_first") (constraint-fn-var 94)
(receiver
(e-list
(elems
(e-string
(e-literal (string "hello")))
(e-string
(e-literal (string "world"))))))
(args
(e-closure
(captures
(capture (ident "letter")))
(e-lambda
(args
(p-assign (ident "letters")))
(e-dispatch-call (method "contains") (constraint-fn-var 92)
(receiver
(e-dispatch-call (method "to_utf8") (constraint-fn-var 90)
(receiver
(e-lookup-local
(p-assign (ident "letters"))))
(args)))
(args
(e-lookup-local
(p-assign (ident "letter"))))))))))
(branches
(branch
(patterns
(pattern (degenerate false)
(p-nominal-external (builtin)
(p-applied-tag))))
(value
(e-lookup-local
(p-assign (ident "#ok")))))
(branch
(patterns
(pattern (degenerate false)
(p-nominal-external (builtin)
(p-applied-tag))))
(value
(e-string
(e-literal (string "")))))))))
(e-lookup-local
(p-assign (ident "val")))))
(annotation
(ty-fn (effectful false)
(ty-lookup (name "U8") (builtin))
(ty-lookup (name "Str") (builtin))))))
~~~
# TYPES
~~~clojure
(inferred-types
(defs
(patt (type "U8 -> Str")))
(expressions
(expr (type "U8 -> Str"))))
~~~
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ It has the type:

List(U64)

But the annotation say it should be:
But the annotation says it should be:

List(Str)

Expand Down
2 changes: 1 addition & 1 deletion test/snapshots/lambda_capture/capture_from_block.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ EndOfFile,
(e-num (value "10")))
(s-let
(p-assign (ident "b"))
(e-call (constraint-fn-var 116)
(e-call (constraint-fn-var 114)
(e-closure
(captures
(capture (ident "a")))
Expand Down
2 changes: 1 addition & 1 deletion test/snapshots/lambda_capture/simple_capture.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ EndOfFile,
(e-num (value "5")))
(s-let
(p-assign (ident "y"))
(e-call (constraint-fn-var 82)
(e-call (constraint-fn-var 80)
(e-closure
(captures
(capture (ident "x")))
Expand Down
Loading