Fix weirdness with typevar declaration not being correctly wrapped

This commit is contained in:
2025-02-15 12:34:56 +01:00
parent 38fbe152a2
commit 3c7f2efabb
2 changed files with 22 additions and 30 deletions

View File

@@ -1,5 +1,5 @@
--deepCopy:on
--exceptions:setjmp
--hints:off
-d:danger
-d:debug
path="src"

View File

@@ -1125,25 +1125,27 @@ proc replaceGenerics(self: TypeChecker, typ: Type, generics: TableRef[string, Ty
proc concretize(self: TypeChecker, name: Name, args: seq[TypedExpr], node: ASTNode = nil): Type =
## Takes in a generic type and its arguments and returns a concrete instantiation
## of it
##
let typ = name.valueType.unwrapType()
case typ.kind:
of Typevar:
return Type(kind: Typevar, wrapped: args[0].kind)
else:
if typ.generics.len() == 0:
self.error(&"cannot create concrete instance of objects of type {self.stringify(typ)} (type is not a generic)")
elif len(args) != typ.generics.len():
self.error(&"invalid number of arguments supplied for generic instantiation (expecting exactly {typ.generics.len()}, got {len(args)} instead)", node=node)
# Construct a concrete copy of the original generic type
result = typ.deepCopy()
var replaced = newTable[string, Type]()
var i = 0
for key in typ.generics.keys():
replaced[key] = self.check(args[i].kind, typ.generics[key], args[i].node)
inc(i)
# Now replaced contains a mapping from the names of the type variables to
# their respective (concrete) type. All we have to do is recursively replace
# every occurrence of them
self.replaceGenerics(typ, replaced)
if typ.generics.len() == 0:
self.error(&"cannot create concrete instance of objects of type {self.stringify(typ)} (type is not a generic)")
elif len(args) != typ.generics.len():
self.error(&"invalid number of arguments supplied for generic instantiation (expecting exactly {typ.generics.len()}, got {len(args)} instead)", node=node)
# Construct a concrete copy of the original generic type
result = typ.deepCopy()
var replaced = newTable[string, Type]()
var i = 0
for key in typ.generics.keys():
replaced[key] = self.check(args[i].kind, typ.generics[key], args[i].node)
inc(i)
# Now replaced contains a mapping from the names of the type variables to
# their respective (concrete) type. All we have to do is recursively replace
# every occurrence of them
self.replaceGenerics(typ, replaced)
proc expandTypeConstraints(self: TypeChecker, condition: Expression, list: var seq[tuple[match: bool, kind: Type, value: Expression]], accept: bool = true) =
## Recursively unpacks a type constraint
@@ -1475,16 +1477,7 @@ proc expression(self: TypeChecker, node: Expression): TypedExpr =
# as generics (and are even declared as such in the stdlib),
# but under the hood they're much simpler (they're just wrappers
# over a type, after all)
let node = GenericExpr(node)
let name = self.find(node.ident.token.lexeme, "typevar".toIntrinsic())
if not name.isNil() and name.valueType.intrinsic:
# Bonus points: if this is a generic, it'll also be handled nicely.
# Recursion is cool!
result = self.infer(node.args[0])
result.node = node
result.kind = result.kind.wrapType()
else:
result = self.genericExpr(GenericExpr(node))
result = self.genericExpr(GenericExpr(node))
of NodeKind.refExpr:
result = self.refExpr(Ref(node))
of NodeKind.ptrExpr:
@@ -1718,8 +1711,7 @@ proc typeDecl(self: TypeChecker, node: TypeDecl, name: Name = nil): TypedTypeDec
result.fields[field.ident.token.lexeme] = newTypedExpr(field.ident, result.parent.valueType.fields[field.ident.token.lexeme])
# Turn the declared type into a typevar so that future references
# to it will be distinct from its instances
if not name.valueType.isTypevar():
name.valueType = name.valueType.wrapType()
name.valueType = name.valueType.wrapType()
# TODO: Check interfaces
self.endScope()