// helper functions internal void SortDeclarationsIntoImplBlock(AstImplBlock impl) { foreach (var decl in impl.Declarations) { decl.Parent = impl; decl.Scope = impl.SubScope; decl.SetFlag(StmtFlags.ExportScope, impl.GetFlag(StmtFlags.ExportScope)); decl.SourceFile = impl.SourceFile; switch (decl) { case AstConstantDeclaration con: { con.Initializer.AttachTo(con); switch (con.Initializer) { case AstFuncExpr func: impl.Functions.Add(func); break; default: ReportError(con.Initializer, $"This type is not allowed here."); break; } break; } default: ReportError(decl, $"This type of declaration is not allowed here."); break; } } }
private void Pass3Impl(AstImplBlock impl) { Log($"Pass3Impl {impl.Accept(new SignatureAstPrinter())}", $"poly = {impl.IsPolymorphic}"); PushLogScope(); try { if (!impl.IsPolyInstance) { impl.SubScope = new Scope($"impl {impl.TraitExpr} for {impl.TargetTypeExpr}", impl.Scope); if (impl.Parameters?.Count > 0) { impl.IsPolymorphic = true; } } // check if there are parameters if (impl.IsPolymorphic) { // setup scopes foreach (var param in impl.Parameters) { param.Scope = impl.Scope; param.TypeExpr.Scope = impl.Scope; param.TypeExpr.SetFlag(ExprFlags.ValueRequired, true); param.TypeExpr = ResolveTypeNow(param.TypeExpr, out var newType, forceInfer: true); if (newType is AbstractType) { continue; } param.Type = newType; switch (param.Type) { case CheezTypeType _: param.Value = new PolyType(param.Name.Name, true); if (param.Name != null) { impl.SubScope.DefineTypeSymbol(param.Name.Name, new PolyType(param.Name.Name, true)); } break; case IntType _: case FloatType _: case BoolType _: case CharType _: case EnumType _: if (param.Name != null) { impl.SubScope.DefineConstant(param.Name.Name, param.Type, new PolyValue(param.Name.Name)); } //impl.SubScope.DefineConstant(param.Name.Name, CheezType.PolyValue, new PolyValue(param.Name.Name)); break; case ErrorType _: break; default: ReportError(param.TypeExpr, $"The type '{param.Type}' is not allowed here."); break; } } } impl.TargetTypeExpr.SetFlag(ExprFlags.ValueRequired, true); impl.TargetTypeExpr.Scope = impl.SubScope; impl.TargetTypeExpr = ResolveTypeNow(impl.TargetTypeExpr, out var t, resolvePolyExprToConcreteType: !impl.IsPolymorphic); impl.TargetType = t; // @TODO: does it make sense to allow conditions on impl blocks without parameters? // for now don't allow these if (impl.Conditions != null) { if (impl.Parameters == null) { ReportError(new Location(impl.Conditions.First().Location.Beginning, impl.Conditions.Last().Location.End), $"An impl block can't have a condition without parameters"); } foreach (var cond in impl.Conditions) { cond.Scope = impl.SubScope; } } if (impl.IsPolymorphic) { return; } impl.SubScope.DefineTypeSymbol("Self", impl.TargetType); SortDeclarationsIntoImplBlock(impl); foreach (var f in impl.Functions) { f.Scope = impl.SubScope; f.ConstScope = new Scope($"fn$ {f.Name}", f.Scope); f.SubScope = new Scope($"fn {f.Name}", f.ConstScope); f.ImplBlock = impl; f.SetFlag(ExprFlags.ExportScope, impl.GetFlag(StmtFlags.ExportScope)); InferTypeFuncExpr(f); CheckForSelfParam(f); impl.Scope.DefineImplFunction(f); impl.SubScope.DefineSymbol(f); } } finally { PopLogScope(); Log($"Finished Pass3Impl {impl.Accept(new SignatureAstPrinter())}", $"poly = {impl.IsPolymorphic}"); } }