diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 40 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 13 | ||||
| -rw-r--r-- | source/slang/slang-check-stmt.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-check.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-lookup.cpp | 6 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 68 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 4 |
7 files changed, 97 insertions, 38 deletions
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index a37d80ae8..99400c17c 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -70,6 +70,8 @@ namespace Slang void visitAssocTypeDecl(AssocTypeDecl* decl); + void checkCallableDeclCommon(CallableDecl* decl); + void visitFuncDecl(FuncDecl* funcDecl); void visitParamDecl(ParamDecl* paramDecl); @@ -149,7 +151,7 @@ namespace Slang void visitEnumDecl(EnumDecl* decl); - void visitFuncDecl(FuncDecl* funcDecl); + void visitFunctionDeclBase(FunctionDeclBase* funcDecl); void visitParamDecl(ParamDecl* paramDecl); }; @@ -1990,11 +1992,11 @@ namespace Slang getSink()->diagnose(decl, Slang::Diagnostics::assocTypeInInterfaceOnly); } - void SemanticsDeclBodyVisitor::visitFuncDecl(FuncDecl* funcDecl) + void SemanticsDeclBodyVisitor::visitFunctionDeclBase(FunctionDeclBase* decl) { - if (auto body = funcDecl->Body) + if (auto body = decl->Body) { - checkBodyStmt(body, funcDecl); + checkBodyStmt(body, decl); } } @@ -2546,6 +2548,14 @@ namespace Slang } } + void SemanticsDeclHeaderVisitor::checkCallableDeclCommon(CallableDecl* decl) + { + for(auto& paramDecl : decl->GetParameters()) + { + ensureDecl(paramDecl, DeclCheckState::ReadyForReference); + } + } + void SemanticsDeclHeaderVisitor::visitFuncDecl(FuncDecl* funcDecl) { auto resultType = funcDecl->ReturnType; @@ -2559,10 +2569,7 @@ namespace Slang } funcDecl->ReturnType = resultType; - for (auto& para : funcDecl->GetParameters()) - { - ensureDecl(para, DeclCheckState::ReadyForReference); - } + checkCallableDeclCommon(funcDecl); } IntegerLiteralValue SemanticsVisitor::GetMinBound(RefPtr<IntVal> val) @@ -2700,6 +2707,7 @@ namespace Slang // significant, and we need to make a choice // sooner or later. // + ensureDecl(extDeclRef, DeclCheckState::CanUseExtensionTargetType); auto targetType = GetTargetType(extDeclRef); return calcThisType(targetType); } @@ -2749,23 +2757,15 @@ namespace Slang void SemanticsDeclHeaderVisitor::visitConstructorDecl(ConstructorDecl* decl) { - for (auto& paramDecl : decl->GetParameters()) - { - ensureDecl(paramDecl, DeclCheckState::CanUseTypeOfValueDecl); - } - // We need to compute the result tyep for this declaration, // since it wasn't filled in for us. decl->ReturnType.type = findResultTypeForConstructorDecl(decl); + + checkCallableDeclCommon(decl); } void SemanticsDeclHeaderVisitor::visitSubscriptDecl(SubscriptDecl* decl) { - for (auto& paramDecl : decl->GetParameters()) - { - ensureDecl(paramDecl, DeclCheckState::CanUseTypeOfValueDecl); - } - decl->ReturnType = CheckUsableType(decl->ReturnType); // If we have a subscript declaration with no accessor declarations, @@ -2789,6 +2789,8 @@ namespace Slang getterDecl->ParentDecl = decl; decl->Members.add(getterDecl); } + + checkCallableDeclCommon(decl); } void SemanticsDeclHeaderVisitor::visitAccessorDecl(AccessorDecl* decl) @@ -2808,6 +2810,8 @@ namespace Slang { getSink()->diagnose(decl, Diagnostics::accessorMustBeInsideSubscriptOrProperty); } + + checkCallableDeclCommon(decl); } GenericDecl* SemanticsVisitor::GetOuterGeneric(Decl* decl) diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 863b5f38a..764f0526a 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -408,7 +408,7 @@ namespace Slang // so that we can add some quality-of-life features for users // in cases where the compiler crashes // - void dispatchStmt(Stmt* stmt, FuncDecl* parentFunc, OuterStmtInfo* outerStmts); + void dispatchStmt(Stmt* stmt, FunctionDeclBase* parentFunc, OuterStmtInfo* outerStmts); void dispatchExpr(Expr* expr); /// Ensure that a declaration has been checked up to some state @@ -781,7 +781,7 @@ namespace Slang // as the tag type for an `enum` void validateEnumTagType(Type* type, SourceLoc const& loc); - void checkStmt(Stmt* stmt, FuncDecl* outerFunction, OuterStmtInfo* outerStmts); + void checkStmt(Stmt* stmt, FunctionDeclBase* outerFunction, OuterStmtInfo* outerStmts); void getGenericParams( GenericDecl* decl, @@ -1369,20 +1369,19 @@ namespace Slang : public SemanticsVisitor , StmtVisitor<SemanticsStmtVisitor> { - SemanticsStmtVisitor(SharedSemanticsContext* shared, FuncDecl* parentFunc, OuterStmtInfo* outerStmts) + SemanticsStmtVisitor(SharedSemanticsContext* shared, FunctionDeclBase* parentFunc, OuterStmtInfo* outerStmts) : SemanticsVisitor(shared) , m_parentFunc(parentFunc) , m_outerStmts(outerStmts) {} /// The parent function (if any) that surrounds the statement being checked. - // TODO: This should probably be a more general case like `CallableDecl` - FuncDecl* m_parentFunc = nullptr; + FunctionDeclBase* m_parentFunc = nullptr; /// The linked list of lexically surrounding statements. OuterStmtInfo* m_outerStmts = nullptr; - FuncDecl* getParentFunc() { return m_parentFunc; } + FunctionDeclBase* getParentFunc() { return m_parentFunc; } void checkStmt(Stmt* stmt); @@ -1433,7 +1432,7 @@ namespace Slang : SemanticsVisitor(shared) {} - void checkBodyStmt(Stmt* stmt, FuncDecl* parentDecl) + void checkBodyStmt(Stmt* stmt, FunctionDeclBase* parentDecl) { checkStmt(stmt, parentDecl, nullptr); } diff --git a/source/slang/slang-check-stmt.cpp b/source/slang/slang-check-stmt.cpp index 7a157a1fd..58d301549 100644 --- a/source/slang/slang-check-stmt.cpp +++ b/source/slang/slang-check-stmt.cpp @@ -35,7 +35,7 @@ namespace Slang }; } - void SemanticsVisitor::checkStmt(Stmt* stmt, FuncDecl* parentDecl, OuterStmtInfo* outerStmts) + void SemanticsVisitor::checkStmt(Stmt* stmt, FunctionDeclBase* parentDecl, OuterStmtInfo* outerStmts) { if (!stmt) return; dispatchStmt(stmt, parentDecl, outerStmts); diff --git a/source/slang/slang-check.cpp b/source/slang/slang-check.cpp index 990f9a0f5..dd28a9d71 100644 --- a/source/slang/slang-check.cpp +++ b/source/slang/slang-check.cpp @@ -223,7 +223,7 @@ namespace Slang translationUnit->getModule()->_collectShaderParams(); } - void SemanticsVisitor::dispatchStmt(Stmt* stmt, FuncDecl* parentFunc, OuterStmtInfo* outerStmts) + void SemanticsVisitor::dispatchStmt(Stmt* stmt, FunctionDeclBase* parentFunc, OuterStmtInfo* outerStmts) { SemanticsStmtVisitor visitor(getShared(), parentFunc, outerStmts); try diff --git a/source/slang/slang-lookup.cpp b/source/slang/slang-lookup.cpp index e860d91d1..49f0bbf0c 100644 --- a/source/slang/slang-lookup.cpp +++ b/source/slang/slang-lookup.cpp @@ -518,7 +518,11 @@ void DoLookupImpl( session, name, containerDeclRef, request, result, breadcrumbs); - if( auto funcDeclRef = containerDeclRef.as<FunctionDeclBase>() ) + if( containerDeclRef.is<ConstructorDecl>() ) + { + thisParameterMode = LookupResultItem::Breadcrumb::ThisParameterMode::Mutating; + } + else if( auto funcDeclRef = containerDeclRef.as<FunctionDeclBase>() ) { if( funcDeclRef.getDecl()->HasModifier<MutatingAttribute>() ) { diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index fdbb2cb27..360376b73 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -804,17 +804,34 @@ LoweredValInfo emitCallToDeclRef( if( auto ctorDeclRef = funcDeclRef.as<ConstructorDecl>() ) { - // HACK: we know all constructors are builtins for now, - // so we need to emit them as a call to the corresponding - // builtin operation. - // - // TODO: these should all either be intrinsic operations, - // or calls to library functions. - - return LoweredValInfo::simple(builder->emitConstructorInst(type, argCount, args)); + if(!ctorDeclRef.getDecl()->Body) + { + // HACK: For legacy reasons, all of the built-in initializers + // in the standard library are declared without proper + // intrinsic-op modifiers, so we will assume that an + // initializer without a body should map to `kIROp_Construct`. + // + // TODO: We should make all the initializers in the + // standard library have either a body or a proper + // intrinsic-op modifier. + // + // TODO: We should eliminate `kIROp_Construct` from the + // IR completely, in favor of more detailed/specific ops + // that cover the cases we actually care about. + // + return LoweredValInfo::simple(builder->emitConstructorInst(type, argCount, args)); + } } // Fallback case is to emit an actual call. + // + // TODO: We are constructing a type that we expect the function + // being called to have here, but that type doesn't account + // for `in` vs. `out`/`inout` parameters, so it could easily + // be wrong. We should sort out why this path in the code + // even needs to be computing a type (rather than taking + // it directly from the declaration). + // if(!funcType) { List<IRType*> argTypes; @@ -6175,15 +6192,46 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> } } - // Lower body + // We will now set about emitting the code for the body of + // the function/callable. + // + // In the case of an initializer ("constructor") declaration, + // the `this` value is not a parameter, but rather a placeholder + // for the value that will be returned. We thus need to set up + // a local variable to represent this value. + // + auto constructorDecl = as<ConstructorDecl>(decl); + if(constructorDecl) + { + auto thisVar = subContext->irBuilder->emitVar(irResultType); + subContext->thisVal = LoweredValInfo::ptr(thisVar); + } + + // We lower whatever statement was stored on the declaration + // as the body of the new IR function. + // lowerStmt(subContext, decl->Body); // We need to carefully add a terminator instruction to the end // of the body, in case the user didn't do so. + // if (!subContext->irBuilder->getBlock()->getTerminator()) { - if(as<IRVoidType>(irResultType)) + if(constructorDecl) + { + // A constructor declaration should return the + // value of the `this` variable that was set + // up at the start. + // + // TODO: This should also apply if any code + // path in an initializer/constructor attempts + // to do an early `return;`. + // + subContext->irBuilder->emitReturn( + getSimpleVal(subContext, subContext->thisVal)); + } + else if(as<IRVoidType>(irResultType)) { // `void`-returning function can get an implicit // return on exit of the body statement. diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index c5420a936..e5a1ad576 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -2447,6 +2447,7 @@ namespace Slang { RefPtr<ConstructorDecl> decl = new ConstructorDecl(); parser->FillPosition(decl.Ptr()); + parser->PushScope(decl); // TODO: we need to make sure that all initializers have // the same name, but that this name doesn't conflict @@ -2462,6 +2463,7 @@ namespace Slang decl->Body = parseOptBody(parser); + parser->PopScope(); return decl; } @@ -2506,6 +2508,7 @@ namespace Slang { RefPtr<SubscriptDecl> decl = new SubscriptDecl(); parser->FillPosition(decl.Ptr()); + parser->PushScope(decl); // TODO: the use of this name here is a bit magical... decl->nameAndLoc.name = getName(parser, "operator[]"); @@ -2533,6 +2536,7 @@ namespace Slang // empty body should be treated like `{ get; }` } + parser->PopScope(); return decl; } |
