Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typechecker: Add support for trait declaration #561

Merged
merged 2 commits into from
Feb 21, 2025
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
28 changes: 22 additions & 6 deletions projects/compiler/src/compiler.abra
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,8 @@ pub type Compiler {
(iter, typedIterator.ty, nextFn, false)
}
}
InstanceKind.Enum(_enum) => todo("enum as for-loop target")
InstanceKind.Enum => todo("enum as for-loop target")
InstanceKind.Trait => unreachable("trait as for-loop target")
}

val nextItemTy = try self._typeIsOption(nextFn.returnType) else unreachable("a 'next' method must return an Option type")
Expand Down Expand Up @@ -1434,6 +1435,7 @@ pub type Compiler {
val getFn = match instanceKind {
InstanceKind.Struct => self._getMethodFunctionByName(instanceKind, "get")
InstanceKind.Enum => unreachable("array-like indexing never applies to enum instances")
InstanceKind.Trait => unreachable("array-like indexing never applies to trait instances")
}
val getFnVal = try self._getOrCompileMethod(instType, getFn)
self._resolvedGenerics.popLayer()
Expand Down Expand Up @@ -1462,6 +1464,7 @@ pub type Compiler {
val getRangeFn = match instanceKind {
InstanceKind.Struct => self._getMethodFunctionByName(instanceKind, "getRange")
InstanceKind.Enum => unreachable("array-like indexing never applies to enum instances")
InstanceKind.Trait => unreachable("array-like indexing never applies to trait instances")
}
val getRangeFnVal = try self._getOrCompileMethod(instType, getRangeFn, paramsNeedingDefaultValue)
self._resolvedGenerics.popLayer()
Expand Down Expand Up @@ -1495,7 +1498,7 @@ pub type Compiler {
val (instanceKind, typeArgs) = try self._getInstanceTypeForType(tupleExpr.ty)
val struct = match instanceKind {
InstanceKind.Struct(struct) => struct
InstanceKind.Enum => unreachable("tuples are represented as structs")
else => unreachable("tuples are represented as structs")
}

val selfType = Type(kind: TypeKind.Instance(InstanceKind.Struct(struct), typeArgs))
Expand Down Expand Up @@ -2062,6 +2065,7 @@ pub type Compiler {
val typeName = match instanceKind {
InstanceKind.Struct(struct) => struct.label.name
InstanceKind.Enum(enum_) => enum_.label.name
InstanceKind.Trait(trait_) => todo()
}
"$typeName.."
} else unreachable("an instance method should have a instanceKind")
Expand All @@ -2070,6 +2074,7 @@ pub type Compiler {
val typeName = match instanceKind {
InstanceKind.Struct(struct) => struct.label.name
InstanceKind.Enum(enum_) => enum_.label.name
InstanceKind.Trait(trait_) => todo()
}
"$typeName."
}
Expand Down Expand Up @@ -3137,7 +3142,7 @@ pub type Compiler {
val (selfTy, typeArgs) = try self._getInstanceTypeForType(selfType)
val (fnStruct, fnCallMethodFn) = match selfTy {
InstanceKind.Struct(struct) => try self._isFunctionStruct(struct) else unreachable("type of fn expr must be a Function struct")
InstanceKind.Enum => unreachable()
else => unreachable("type of fn expr must be a Function struct")
}

var methodName = try self._structMethodFnName(fnStruct, fnCallMethodFn)
Expand Down Expand Up @@ -3313,6 +3318,7 @@ pub type Compiler {

(try self._enumMethodFnName(enum_, fn), fn)
}
InstanceKind.Trait(trait_) => todo("_getOrCompileToStringMethod for trait")
}
if self._builder.getFunction(methodName) |fn| return Ok(fn)

Expand Down Expand Up @@ -3736,6 +3742,7 @@ pub type Compiler {

(try self._enumMethodFnName(enum_, fn), fn)
}
InstanceKind.Trait(trait_) => todo("_getOrCompileEqMethod for trait")
}
if self._builder.getFunction(methodName) |fn| return Ok(fn)

Expand Down Expand Up @@ -3969,6 +3976,7 @@ pub type Compiler {

(try self._enumMethodFnName(enum_, fn), fn)
}
InstanceKind.Trait(trait_) => todo("_getOrCompileHashMethod for trait")
}
if self._builder.getFunction(methodName) |fn| return Ok(fn)

Expand Down Expand Up @@ -4170,13 +4178,15 @@ pub type Compiler {

(template, inst)
}
InstanceKind.Trait(trait_) => todo("_addResolvedGenericsLayerForInstanceMethod for trait")
}
for (name, ty) in selfInstanceType.extractGenerics(template) {
resolvedGenerics[name] = ty
}
val layerName = match instanceKind {
InstanceKind.Struct(struct) => "${struct.label.name}.$methodName"
InstanceKind.Enum(enum_) => "${enum_.label.name}.$methodName"
InstanceKind.Trait(trait_) => todo("_addResolvedGenericsLayerForInstanceMethod for trait")
}
match self._resolvedGenerics.addLayer(layerName, resolvedGenerics) { Ok => {}, Err(e) => return Err(CompileError(position: position, kind: CompileErrorKind.ResolvedGenericsError(context: layerName, message: e))) }

Expand All @@ -4186,7 +4196,6 @@ pub type Compiler {
func _addResolvedGenericsLayerForEnumVariant(self, ty: Type, variantName: String, position: Position, resolvedGenerics: Map<String, Type> = {}): Result<Type, CompileError> {
val (instanceKind, typeArgs) = try self._getInstanceTypeForType(ty)
match instanceKind {
InstanceKind.Struct => unreachable("type should always be an enum here")
InstanceKind.Enum(enum_) => {
val template = Type(kind: TypeKind.Instance(instanceKind, enum_.typeParams.map(name => Type(kind: TypeKind.Generic(name)))))
val selfInstanceType = Type(kind: TypeKind.Instance(instanceKind, typeArgs))
Expand All @@ -4200,6 +4209,7 @@ pub type Compiler {

Ok(selfInstanceType)
}
else => unreachable("type should always be an enum here")
}
}

Expand Down Expand Up @@ -4291,7 +4301,8 @@ pub type Compiler {
TypeKind.Instance(instanceKind, typeParams) => {
val n = match instanceKind {
InstanceKind.Struct(struct) => struct.label.name
InstanceKind.Enum(_enum) => _enum.label.name
InstanceKind.Enum(enum_) => enum_.label.name
InstanceKind.Trait(trait_) => trait_.label.name
}
if !typeParams.isEmpty() {
val params: String[] = []
Expand Down Expand Up @@ -4327,7 +4338,8 @@ pub type Compiler {
TypeKind.Instance(instanceKind, typeParams) => {
val n = match instanceKind {
InstanceKind.Struct(struct) => struct.label.name
InstanceKind.Enum(_enum) => _enum.label.name
InstanceKind.Enum(enum_) => enum_.label.name
InstanceKind.Trait(trait_) => trait_.label.name
}
if !typeParams.isEmpty() {
val params: String[] = []
Expand Down Expand Up @@ -4368,11 +4380,13 @@ pub type Compiler {
FunctionKind.InstanceMethod(structOrEnumOpt, _) => match structOrEnumOpt {
InstanceKind.Struct(s) => "${s.label.name}.$name"
InstanceKind.Enum(e) => "${e.label.name}.$name"
InstanceKind.Trait(t) => todo("_functionName for trait")
_ => name
}
FunctionKind.StaticMethod(instanceKind, _) => match instanceKind {
InstanceKind.Struct(s) => "${s.label.name}#$name"
InstanceKind.Enum(e) => "${e.label.name}#$name"
InstanceKind.Trait(t) => todo("_functionName for trait")
}
}
}
Expand Down Expand Up @@ -4466,6 +4480,7 @@ pub type Compiler {
match instanceKind {
InstanceKind.Struct(struct) => self._structMethodFnName(struct, fn)
InstanceKind.Enum(enum_) => self._enumMethodFnName(enum_, fn)
InstanceKind.Trait(trait_) => todo("_methodFnName for trait")
}
}

Expand Down Expand Up @@ -4587,6 +4602,7 @@ pub type Compiler {
val (parentName, methods) = match parent {
InstanceKind.Struct(s) => (s.label.name, if staticMethod s.staticMethods else s.instanceMethods)
InstanceKind.Enum(e) => (e.label.name, if staticMethod e.staticMethods else e.instanceMethods)
InstanceKind.Trait(t) => todo("_getMethodFunctionByName for trait")
}

try methods.find(m => m.label.name == name) else {
Expand Down
4 changes: 2 additions & 2 deletions projects/compiler/src/parser.abra
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ pub type Parser {
try self._parseDecorator()

val nextToken = try self._expectPeek()
val expected = [TokenKind.Val, TokenKind.Var, TokenKind.Func, TokenKind.Type, TokenKind.Enum, TokenKind.Decorator, TokenKind.At, TokenKind.Pub]
val expected = [TokenKind.Val, TokenKind.Var, TokenKind.Func, TokenKind.Type, TokenKind.Enum, TokenKind.Trait, TokenKind.Decorator, TokenKind.At, TokenKind.Pub]
if !expected.contains(nextToken.kind) {
return Err(ParseError(position: nextToken.position, kind: ParseErrorKind.ExpectedToken(expected, nextToken.kind)))
}
Expand All @@ -521,7 +521,7 @@ pub type Parser {
self._advance() // consume 'pub' token

val nextToken = try self._expectPeek()
val expected = [TokenKind.Val, TokenKind.Var, TokenKind.Func, TokenKind.Type, TokenKind.Enum, TokenKind.Decorator]
val expected = [TokenKind.Val, TokenKind.Var, TokenKind.Func, TokenKind.Type, TokenKind.Enum, TokenKind.Trait, TokenKind.Decorator]
if !expected.contains(nextToken.kind) {
return Err(ParseError(position: nextToken.position, kind: ParseErrorKind.ExpectedToken(expected, nextToken.kind)))
}
Expand Down
Loading