mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-23 08:48:03 +00:00
The root cause was that numeric literals with `from_numeral` constraints were being generalized (let-polymorphism), causing each lookup to create a fresh instantiation. This meant constraints from later usage (like List.get expecting U64) didn't propagate back to the original definition, leaving the value as an unconstrained flex var that defaulted to Dec. Fix: 1. In generalize.zig: Don't generalize flex vars with `from_numeral` constraints at ANY rank (not just top_level) 2. In Check.zig: Don't instantiate during lookup if the var has a `from_numeral` constraint - unify directly instead This aligns with the design that let-generalization should only work for things that are syntactically lambdas (e.g. `foo = |arg| ...`). Also reverts the interpreter workaround - the proper fix is in the type checker, not working around type system bugs in the interpreter. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1.9 KiB
1.9 KiB
META
description=Numeric without let-generalization gives type error (only lambdas get let-generalization)
type=expr
SOURCE
{
n = 42
a = I64.to_str(n)
b = Dec.to_str(n)
Str.concat(a, b)
}
EXPECTED
TYPE MISMATCH - numeric_let_generalize_in_block.md:4:20:4:21
PROBLEMS
TYPE MISMATCH The first argument being passed to this function has the wrong type: numeric_let_generalize_in_block.md:4:20:4:21:
b = Dec.to_str(n)
^
This argument has the type: I64
But the function needs the first argument to be: Dec
TOKENS
OpenCurly,
LowerIdent,OpAssign,Int,
LowerIdent,OpAssign,UpperIdent,NoSpaceDotLowerIdent,NoSpaceOpenRound,LowerIdent,CloseRound,
LowerIdent,OpAssign,UpperIdent,NoSpaceDotLowerIdent,NoSpaceOpenRound,LowerIdent,CloseRound,
UpperIdent,NoSpaceDotLowerIdent,NoSpaceOpenRound,LowerIdent,Comma,LowerIdent,CloseRound,
CloseCurly,
EndOfFile,
PARSE
(e-block
(statements
(s-decl
(p-ident (raw "n"))
(e-int (raw "42")))
(s-decl
(p-ident (raw "a"))
(e-apply
(e-ident (raw "I64.to_str"))
(e-ident (raw "n"))))
(s-decl
(p-ident (raw "b"))
(e-apply
(e-ident (raw "Dec.to_str"))
(e-ident (raw "n"))))
(e-apply
(e-ident (raw "Str.concat"))
(e-ident (raw "a"))
(e-ident (raw "b")))))
FORMATTED
{
n = 42
a = I64.to_str(n)
b = Dec.to_str(n)
Str.concat(a, b)
}
CANONICALIZE
(e-block
(s-let
(p-assign (ident "n"))
(e-num (value "42")))
(s-let
(p-assign (ident "a"))
(e-call
(e-lookup-external
(builtin))
(e-lookup-local
(p-assign (ident "n")))))
(s-let
(p-assign (ident "b"))
(e-call
(e-lookup-external
(builtin))
(e-lookup-local
(p-assign (ident "n")))))
(e-call
(e-lookup-external
(builtin))
(e-lookup-local
(p-assign (ident "a")))
(e-lookup-local
(p-assign (ident "b")))))
TYPES
(expr (type "Error"))