diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/core.meta.slang | 7 | ||||
| -rw-r--r-- | source/slang/core.meta.slang.h | 9 | ||||
| -rw-r--r-- | source/slang/slang-check-conversion.cpp | 14 | ||||
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 491 | ||||
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 31 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 8 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 3 | ||||
| -rw-r--r-- | source/slang/slang-syntax.h | 12 |
8 files changed, 369 insertions, 206 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 58e6e287c..85eb82576 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -359,7 +359,12 @@ for (int N = 2; N <= 4; ++N) sb << ", vector<T," << K << "> "; for (int ii = 0; ii < K; ++ii) { - sb << kComponentNames[ii]; + // The component names for the second parameter + // must start at `M`, so that we get signatures like: + // + // __init(float2 xy, float2 zw) + // + sb << kComponentNames[M + ii]; } sb << ");\n"; } diff --git a/source/slang/core.meta.slang.h b/source/slang/core.meta.slang.h index 201429700..b8d7d5d9c 100644 --- a/source/slang/core.meta.slang.h +++ b/source/slang/core.meta.slang.h @@ -380,7 +380,12 @@ for (int N = 2; N <= 4; ++N) sb << ", vector<T," << K << "> "; for (int ii = 0; ii < K; ++ii) { - sb << kComponentNames[ii]; + // The component names for the second parameter + // must start at `M`, so that we get signatures like: + // + // __init(float2 xy, float2 zw) + // + sb << kComponentNames[M + ii]; } sb << ");\n"; } @@ -1277,7 +1282,7 @@ for (auto op : binaryOps) sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << leftQual << "matrix<" << leftType << ",N,M> left, " << rightType << " right);\n"; } } -SLANG_RAW("#line 1259 \"core.meta.slang\"") +SLANG_RAW("#line 1264 \"core.meta.slang\"") SLANG_RAW("\n") SLANG_RAW("\n") SLANG_RAW("// Specialized function\n") diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 85c508d41..4b781643e 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -461,7 +461,19 @@ namespace Slang { if(outToExpr) { - getSink()->diagnose(fromExpr->loc, Diagnostics::typeMismatch, toType, fromExpr->type); + // As a special case, if the expression we are trying to convert + // from is overloaded (implying an ambiguous reference), then we + // will try to produce a more appropriately tailored error message. + // + auto fromType = fromExpr->type.type; + if( as<OverloadGroupType>(fromType) ) + { + diagnoseAmbiguousReference(fromExpr); + } + else + { + getSink()->diagnose(fromExpr->loc, Diagnostics::typeMismatch, toType, fromExpr->type); + } } return false; } diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 7c8322fa7..dbc96f9b1 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -81,6 +81,27 @@ namespace Slang void visitAccessorDecl(AccessorDecl* decl); }; + struct SemanticsDeclRedeclarationVisitor + : public SemanticsDeclVisitorBase + , public DeclVisitor<SemanticsDeclRedeclarationVisitor> + { + SemanticsDeclRedeclarationVisitor(SharedSemanticsContext* shared) + : SemanticsDeclVisitorBase(shared) + {} + + void visitDecl(Decl*) {} + void visitDeclGroup(DeclGroup*) {} + +#define CASE(TYPE) void visit##TYPE(TYPE* decl) { checkForRedeclaration(decl); } + + CASE(FuncDecl) + CASE(VarDeclBase) + CASE(SimpleTypeDecl) + CASE(AggTypeDecl) + +#undef CASE + }; + struct SemanticsDeclBasesVisitor : public SemanticsDeclVisitorBase , public DeclVisitor<SemanticsDeclBasesVisitor> @@ -2179,214 +2200,310 @@ namespace Slang return subst; } - void SemanticsVisitor::ValidateFunctionRedeclaration(FuncDecl* funcDecl) + Result SemanticsVisitor::checkFuncRedeclaration( + FuncDecl* newDecl, + FuncDecl* oldDecl) { - auto parentDecl = funcDecl->ParentDecl; - SLANG_ASSERT(parentDecl); - if (!parentDecl) return; + // There are a few different cases that this function needs + // to check for: + // + // * If `newDecl` and `oldDecl` have different signatures such + // that they can always be distinguished at call sites, then + // they don't conflict and don't count as redeclarations. + // + // * If `newDecl` and `oldDecl` have matching signatures, but + // differ in return type (or other details that would affect + // compatibility), then the declarations conflict and an + // error needs to be diagnosed. + // + // * If `newDecl` and `oldDecl` have matching/compatible sigantures, + // but differ when it comes to target-specific overloading, + // then they can co-exist. + // + // * If `newDecl` and `oldDecl` have matching/compatible signatures + // and are specialized for the same target(s), then only + // one can have a body (in which case the other is a forward declaration), + // or else we have a redefinition error. + + auto newGenericDecl = as<GenericDecl>(newDecl->ParentDecl); + auto oldGenericDecl = as<GenericDecl>(oldDecl->ParentDecl); + + // If one declaration is a prefix/postfix operator, and the + // other is not a matching operator, then don't consider these + // to be re-declarations. + // + // Note(tfoley): Any attempt to call such an operator using + // ordinary function-call syntax (if we decided to allow it) + // would be ambiguous in such a case, of course. + // + if (newDecl->HasModifier<PrefixModifier>() != oldDecl->HasModifier<PrefixModifier>()) + return SLANG_OK; + if (newDecl->HasModifier<PostfixModifier>() != oldDecl->HasModifier<PostfixModifier>()) + return SLANG_OK; - Decl* childDecl = funcDecl; + // If one is generic and the other isn't, then there is no match. + if ((newGenericDecl != nullptr) != (oldGenericDecl != nullptr)) + return SLANG_OK; - // If this is a generic function (that is, its parent - // declaration is a generic), then we need to look - // for sibling declarations of the parent. - auto genericDecl = as<GenericDecl>(parentDecl); - if (genericDecl) + // We are going to be comparing the signatures of the + // two functions, but if they are *generic* functions + // then we will need to compare them with consistent + // specializations in place. + // + // We'll go ahead and create some (unspecialized) declaration + // references here, just to be prepared. + // + DeclRef<FuncDecl> newDeclRef(newDecl, nullptr); + DeclRef<FuncDecl> oldDeclRef(oldDecl, nullptr); + + // If we are working with generic functions, then we need to + // consider if their generic signatures match. + if(newGenericDecl) { - parentDecl = genericDecl->ParentDecl; - childDecl = genericDecl; + SLANG_ASSERT(oldGenericDecl); // already checked above + if(!doGenericSignaturesMatch(newGenericDecl, oldGenericDecl)) + return SLANG_OK; + + // Now we need specialize the declaration references + // consistently, so that we can compare. + // + // First we create a "dummy" set of substitutions that + // just reference the parameters of the first generic. + // + auto subst = createDummySubstitutions(newGenericDecl); + // + // Then we use those parameters to specialize the *other* + // generic. + // + subst->genericDecl = oldGenericDecl; + oldDeclRef.substitutions.substitutions = subst; + // + // One way to think about it is that if we have these + // declarations (ignore the name differences...): + // + // // oldDecl: + // void foo1<T>(T x); + // + // // newDecl: + // void foo2<U>(U x); + // + // Then we will compare `foo2` against `foo1<U>`. } - // Look at previously-declared functions with the same name, - // in the same container + // If the parameter signatures don't match, then don't worry + if (!doFunctionSignaturesMatch(newDeclRef, oldDeclRef)) + return SLANG_OK; + + // If we get this far, then we've got two declarations in the same + // scope, with the same name and signature, so they appear + // to be redeclarations. // - // Note: there is an assumption here that declarations that - // occur earlier in the program text will be *later* in - // the linked list of declarations with the same name. - // We are also assuming/requiring that the check here is - // symmetric, in that it is okay to test (A,B) or (B,A), - // and there is no need to test both. + // We will track that redeclaration occured, so that we can + // take it into account for overload resolution. // - buildMemberDictionary(parentDecl); - for (auto pp = childDecl->nextInContainerWithSameName; pp; pp = pp->nextInContainerWithSameName) + // A huge complication that we'll need to deal with is that + // multiple declarations might introduce default values for + // (different) parameters, and we might need to merge across + // all of them (which could get complicated if defaults for + // parameters can reference earlier parameters). + + // If the previous declaration wasn't already recorded + // as being part of a redeclaration family, then make + // it the primary declaration of a new family. + if (!oldDecl->primaryDecl) { - auto prevDecl = pp; + oldDecl->primaryDecl = oldDecl; + } - // Look through generics to the declaration underneath - auto prevGenericDecl = as<GenericDecl>(prevDecl); - if (prevGenericDecl) - prevDecl = prevGenericDecl->inner.Ptr(); + // The new declaration will belong to the family of + // the previous one, and so it will share the same + // primary declaration. + newDecl->primaryDecl = oldDecl->primaryDecl; + newDecl->nextDecl = nullptr; - // We only care about previously-declared functions - // Note(tfoley): although we should really error out if the - // name is already in use for something else, like a variable... - auto prevFuncDecl = as<FuncDecl>(prevDecl); - if (!prevFuncDecl) - continue; + // Next we want to chain the new declaration onto + // the linked list of redeclarations. + auto link = &oldDecl->nextDecl; + while (*link) + link = &(*link)->nextDecl; + *link = newDecl; - // If one declaration is a prefix/postfix operator, and the - // other is not a matching operator, then don't consider these - // to be re-declarations. - // - // Note(tfoley): Any attempt to call such an operator using - // ordinary function-call syntax (if we decided to allow it) - // would be ambiguous in such a case, of course. - // - if (funcDecl->HasModifier<PrefixModifier>() != prevDecl->HasModifier<PrefixModifier>()) - continue; - if (funcDecl->HasModifier<PostfixModifier>() != prevDecl->HasModifier<PostfixModifier>()) - continue; + // Now that we've added things to a group of redeclarations, + // we can do some additional validation. - // If one is generic and the other isn't, then there is no match. - if ((genericDecl != nullptr) != (prevGenericDecl != nullptr)) - continue; + // First, we will ensure that the return types match + // between the declarations, so that they are truly + // interchangeable. + // + // Note(tfoley): If we ever decide to add a beefier type + // system to Slang, we might allow overloads like this, + // so long as the desired result type can be disambiguated + // based on context at the call type. In that case we would + // consider result types earlier, as part of the signature + // matching step. + // + auto resultType = GetResultType(newDeclRef); + auto prevResultType = GetResultType(oldDeclRef); + if (!resultType->Equals(prevResultType)) + { + // Bad redeclaration + getSink()->diagnose(newDecl, Diagnostics::functionRedeclarationWithDifferentReturnType, newDecl->getName(), resultType, prevResultType); + getSink()->diagnose(oldDecl, Diagnostics::seePreviousDeclarationOf, newDecl->getName()); - // We are going to be comparing the signatures of the - // two functions, but if they are *generic* functions - // then we will need to compare them with consistent - // specializations in place. - // - // We'll go ahead and create some (unspecialized) declaration - // references here, just to be prepared. - DeclRef<FuncDecl> funcDeclRef(funcDecl, nullptr); - DeclRef<FuncDecl> prevFuncDeclRef(prevFuncDecl, nullptr); - - // If we are working with generic functions, then we need to - // consider if their generic signatures match. - if (genericDecl) - { - SLANG_ASSERT(prevGenericDecl); // already checked above - if (!doGenericSignaturesMatch(genericDecl, prevGenericDecl)) - continue; + // Don't bother emitting other errors at this point + return SLANG_FAIL; + } - // Now we need specialize the declaration references - // consistently, so that we can compare. - // - // First we create a "dummy" set of substitutions that - // just reference the parameters of the first generic. - auto subst = createDummySubstitutions(genericDecl); - // - // Then we use those parameters to specialize the *other* - // generic. - // - subst->genericDecl = prevGenericDecl; - prevFuncDeclRef.substitutions.substitutions = subst; - // - // One way to think about it is that if we have these - // declarations (ignore the name differences...): - // - // // prevFuncDecl: - // void foo1<T>(T x); - // - // // funcDecl: - // void foo2<U>(U x); - // - // Then we will compare `foo2` against `foo1<U>`. - } + // TODO: Enforce that the new declaration had better + // not specify a default value for any parameter that + // already had a default value in a prior declaration. - // If the parameter signatures don't match, then don't worry - if (!doFunctionSignaturesMatch(funcDeclRef, prevFuncDeclRef)) - continue; + // We are going to want to enforce that we cannot have + // two declarations of a function both specify bodies. + // Before we make that check, however, we need to deal + // with the case where the two function declarations + // might represent different target-specific versions + // of a function. + // + // TODO: if the two declarations are specialized for + // different targets, then skip the body checks below. + // + // ???: Why isn't this problem showing up in practice? - // If we get this far, then we've got two declarations in the same - // scope, with the same name and signature, so they appear - // to be redeclarations. - // - // We will track that redeclaration occured, so that we can - // take it into account for overload resolution. - // - // A huge complication that we'll need to deal with is that - // multiple declarations might introduce default values for - // (different) parameters, and we might need to merge across - // all of them (which could get complicated if defaults for - // parameters can reference earlier parameters). - - // If the previous declaration wasn't already recorded - // as being part of a redeclaration family, then make - // it the primary declaration of a new family. - if (!prevFuncDecl->primaryDecl) + // If both of the declarations have a body, then there + // is trouble, because we wouldn't know which one to + // use during code generation. + if (newDecl->Body && oldDecl->Body) + { + // Redefinition + getSink()->diagnose(newDecl, Diagnostics::functionRedefinition, newDecl->getName()); + getSink()->diagnose(oldDecl, Diagnostics::seePreviousDefinitionOf, newDecl->getName()); + + // Don't bother emitting other errors + return SLANG_FAIL; + } + + // At this point we've processed the redeclaration and + // put it into a group, so there is no reason to keep + // looping and looking at prior declarations. + // + // While no diagnostics have been emitted, we return + // a failure result from the operation to indicate + // to the caller that they should stop looping over + // declarations at this point. + // + return SLANG_FAIL; + } + + Result SemanticsVisitor::checkRedeclaration(Decl* newDecl, Decl* oldDecl) + { + // If either of the declarations being looked at is generic, then + // we want to consider the "inner" declaration instead when + // making decisions about what to allow or not. + // + if(auto newGenericDecl = as<GenericDecl>(newDecl)) + newDecl = newGenericDecl->inner; + if(auto oldGenericDecl = as<GenericDecl>(oldDecl)) + oldDecl = oldGenericDecl->inner; + + // Functions are special in that we can have many declarations + // with the same name in a given scope, and it is possible + // for them to co-exist as overloads, or even just be multiple + // declarations of the same function (thanks to the inherited + // legacy of C forward declarations). + // + // If both declarations are functions, we will check that + // they are allowed to co-exist using these more nuanced rules. + // + if( auto newFuncDecl = as<FuncDecl>(newDecl) ) + { + if(auto oldFuncDecl = as<FuncDecl>(oldDecl) ) { - prevFuncDecl->primaryDecl = prevFuncDecl; + // Both new and old declarations are functions, + // so redeclaration may be valid. + return checkFuncRedeclaration(newFuncDecl, oldFuncDecl); } + } - // The new declaration will belong to the family of - // the previous one, and so it will share the same - // primary declaration. - funcDecl->primaryDecl = prevFuncDecl->primaryDecl; - funcDecl->nextDecl = nullptr; - - // Next we want to chain the new declaration onto - // the linked list of redeclarations. - auto link = &prevFuncDecl->nextDecl; - while (*link) - link = &(*link)->nextDecl; - *link = funcDecl; - - // Now that we've added things to a group of redeclarations, - // we can do some additional validation. - - // First, we will ensure that the return types match - // between the declarations, so that they are truly - // interchangeable. - // - // Note(tfoley): If we ever decide to add a beefier type - // system to Slang, we might allow overloads like this, - // so long as the desired result type can be disambiguated - // based on context at the call type. In that case we would - // consider result types earlier, as part of the signature - // matching step. + // For all other flavors of declaration, we do not + // allow duplicate declarations with the same name. + // + // TODO: We might consider allowing some other cases + // of overloading that can be safely disambiguated: + // + // * A type and a value (function/variable/etc.) of the same name can usually + // co-exist because we can distinguish which is needed by context. + // + // * Multiple generic types with the same name can co-exist + // if their generic parameter lists are sufficient to + // tell them apart at a use site. + + // We will diagnose a redeclaration error at the new declaration, + // and point to the old declaration for context. + // + getSink()->diagnose(newDecl, Diagnostics::redeclaration, newDecl->getName()); + getSink()->diagnose(oldDecl, Diagnostics::seePreviousDeclarationOf, oldDecl->getName()); + return SLANG_FAIL; + } + + + void SemanticsVisitor::checkForRedeclaration(Decl* decl) + { + // We want to consider a "new" declaration in the context + // of some parent/container declaration, and compare it + // to pre-existing "old" declarations of the same name + // in the same container. + // + auto newDecl = decl; + auto parentDecl = decl->ParentDecl; + + // Sanity check: there should always be a parent declaration. + // + SLANG_ASSERT(parentDecl); + if (!parentDecl) return; + + // If the declaration is the "inner" declaration of a generic, + // then we actually want to look one level up, because the + // peers/siblings of the declaration will belong to the same + // parent as the generic, not to the generic. + // + if( auto genericParentDecl = as<GenericDecl>(parentDecl) ) + { + // Note: we need to check here to be sure `newDecl` + // is the "inner" declaration and not one of the + // generic parameters, or else we will end up + // checking them at the wrong scope. // - auto resultType = GetResultType(funcDeclRef); - auto prevResultType = GetResultType(prevFuncDeclRef); - if (!resultType->Equals(prevResultType)) + if( newDecl == genericParentDecl->inner ) { - // Bad redeclaration - getSink()->diagnose(funcDecl, Diagnostics::functionRedeclarationWithDifferentReturnType, funcDecl->getName(), resultType, prevResultType); - getSink()->diagnose(prevFuncDecl, Diagnostics::seePreviousDeclarationOf, funcDecl->getName()); - - // Don't bother emitting other errors at this point - break; + newDecl = parentDecl; + parentDecl = genericParentDecl->ParentDecl; } + } - // Note(tfoley): several of the following checks should - // really be looping over all the previous declarations - // in the same group, and not just the one previous - // declaration we found just now. - - // TODO: Enforce that the new declaration had better - // not specify a default value for any parameter that - // already had a default value in a prior declaration. - - // We are going to want to enforce that we cannot have - // two declarations of a function both specify bodies. - // Before we make that check, however, we need to deal - // with the case where the two function declarations - // might represent different target-specific versions - // of a function. + // We will now look for other declarations with + // the same name in the same parent/container. + // + buildMemberDictionary(parentDecl); + for (auto oldDecl = newDecl->nextInContainerWithSameName; oldDecl; oldDecl = oldDecl->nextInContainerWithSameName) + { + // For each matching declaration, we will check + // whether the redeclaration should be allowed, + // and emit an appropriate diagnostic if not. // - // TODO: if the two declarations are specialized for - // different targets, then skip the body checks below. - - // If both of the declarations have a body, then there - // is trouble, because we wouldn't know which one to - // use during code generation. - if (funcDecl->Body && prevFuncDecl->Body) - { - // Redefinition - getSink()->diagnose(funcDecl, Diagnostics::functionRedefinition, funcDecl->getName()); - getSink()->diagnose(prevFuncDecl, Diagnostics::seePreviousDefinitionOf, funcDecl->getName()); + Result checkResult = checkRedeclaration(newDecl, oldDecl); - // Don't bother emitting other errors + // The `checkRedeclaration` function will return a failure + // status (whether or not it actually emitted a diagnostic) + // if we should stop checking further redeclarations, because + // the declaration in question has been dealt with fully. + // + if(SLANG_FAILED(checkResult)) break; - } - - // At this point we've processed the redeclaration and - // put it into a group, so there is no reason to keep - // looping and looking at prior declarations. - return; } } + void SemanticsDeclHeaderVisitor::visitParamDecl(ParamDecl* paramDecl) { // TODO: This logic should be shared with the other cases of @@ -2456,22 +2573,10 @@ namespace Slang } funcDecl->ReturnType = resultType; - - HashSet<Name*> paraNames; for (auto & para : funcDecl->GetParameters()) { ensureDecl(para, DeclCheckState::ReadyForReference); - - if (paraNames.Contains(para->getName())) - { - getSink()->diagnose(para, Diagnostics::parameterAlreadyDefined, para->getName()); - } - else - paraNames.Add(para->getName()); } - - // One last bit of validation: check if we are redeclaring an existing function - ValidateFunctionRedeclaration(funcDecl); } IntegerLiteralValue SemanticsVisitor::GetMinBound(RefPtr<IntVal> val) @@ -2936,10 +3041,14 @@ namespace Slang SemanticsDeclModifiersVisitor(shared).dispatch(decl); break; - case DeclCheckState::ReadyForReference: + case DeclCheckState::SignatureChecked: SemanticsDeclHeaderVisitor(shared).dispatch(decl); break; + case DeclCheckState::ReadyForReference: + SemanticsDeclRedeclarationVisitor(shared).dispatch(decl); + break; + case DeclCheckState::ReadyForLookup: SemanticsDeclBasesVisitor(shared).dispatch(decl); break; diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index e7db665ae..ebc3a3ef9 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -435,6 +435,29 @@ namespace Slang return result; } + void SemanticsVisitor::diagnoseAmbiguousReference(OverloadedExpr* overloadedExpr, LookupResult const& lookupResult) + { + getSink()->diagnose(overloadedExpr, Diagnostics::ambiguousReference, lookupResult.items[0].declRef.GetName()); + + for(auto item : lookupResult.items) + { + String declString = getDeclSignatureString(item); + getSink()->diagnose(item.declRef, Diagnostics::overloadCandidate, declString); + } + } + + void SemanticsVisitor::diagnoseAmbiguousReference(Expr* expr) + { + if( auto overloadedExpr = as<OverloadedExpr>(expr) ) + { + diagnoseAmbiguousReference(overloadedExpr, overloadedExpr->lookupResult2); + } + else + { + getSink()->diagnose(expr, Diagnostics::ambiguousExpression); + } + } + RefPtr<Expr> SemanticsVisitor::_resolveOverloadedExprImpl(RefPtr<OverloadedExpr> overloadedExpr, LookupMask mask, DiagnosticSink* diagSink) { auto lookupResult = overloadedExpr->lookupResult2; @@ -474,13 +497,7 @@ namespace Slang // if( diagSink ) { - getSink()->diagnose(overloadedExpr, Diagnostics::ambiguousReference, lookupResult.items[0].declRef.GetName()); - - for(auto item : lookupResult.items) - { - String declString = getDeclSignatureString(item); - getSink()->diagnose(item.declRef, Diagnostics::overloadCandidate, declString); - } + diagnoseAmbiguousReference(overloadedExpr, lookupResult); // TODO(tfoley): should we construct a new ErrorExpr here? return CreateErrorExpr(overloadedExpr); diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index e4d49b1e6..863b5f38a 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -382,6 +382,10 @@ namespace Slang /// Worker reoutine for `maybeResolveOverloadedExpr` and `resolveOverloadedExpr`. RefPtr<Expr> _resolveOverloadedExprImpl(RefPtr<OverloadedExpr> overloadedExpr, LookupMask mask, DiagnosticSink* diagSink); + void diagnoseAmbiguousReference(OverloadedExpr* overloadedExpr, LookupResult const& lookupResult); + void diagnoseAmbiguousReference(Expr* overloadedExpr); + + RefPtr<Expr> ExpectATypeRepr(RefPtr<Expr> expr); RefPtr<Type> ExpectAType(RefPtr<Expr> expr); @@ -797,7 +801,9 @@ namespace Slang RefPtr<GenericSubstitution> createDummySubstitutions( GenericDecl* genericDecl); - void ValidateFunctionRedeclaration(FuncDecl* funcDecl); + Result checkRedeclaration(Decl* newDecl, Decl* oldDecl); + Result checkFuncRedeclaration(FuncDecl* newDecl, FuncDecl* oldDecl); + void checkForRedeclaration(Decl* decl); RefPtr<Expr> checkPredicateExpr(Expr* expr); diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index cc93ccc3b..430423464 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -212,7 +212,6 @@ DIAGNOSTIC(20011, Error, unexpectedColon, "unexpected ':'.") // 3xxxx - Semantic analysis // -DIAGNOSTIC(30002, Error, parameterAlreadyDefined, "parameter '$0' already defined.") DIAGNOSTIC(30003, Error, breakOutsideLoop, "'break' must appear inside loop constructs.") DIAGNOSTIC(30004, Error, continueOutsideLoop, "'continue' must appear inside loop constructs.") DIAGNOSTIC(30005, Error, whilePredicateTypeError, "'while': expression must evaluate to int.") @@ -256,6 +255,7 @@ DIAGNOSTIC(30060, Error, expectedAType, "expected a type got a '$0'") DIAGNOSTIC(30100, Error, staticRefToNonStaticMember, "type '$0' cannot be used to refer to non-static member '$1'") +DIAGNOSTIC(30200, Error, redeclaration, "declaration of '$0' conflicts with existing declaration") DIAGNOSTIC(30201, Error, functionRedefinition, "function '$0' already has a body") DIAGNOSTIC(30202, Error, functionRedeclarationWithDifferentReturnType, "function '$0' declared to return '$1' was previously declared to return '$2'") @@ -341,6 +341,7 @@ DIAGNOSTIC(39999, Note, genericSignatureTried, "see declaration of $0") DIAGNOSTIC(39999, Error, expectedAnInterfaceGot, "expected an interface, got '$0'") DIAGNOSTIC(39999, Error, ambiguousReference, "ambiguous reference to '$0'"); +DIAGNOSTIC(39999, Error, ambiguousExpression, "ambiguous reference"); DIAGNOSTIC(39999, Error, declarationDidntDeclareAnything, "declaration does not declare anything"); diff --git a/source/slang/slang-syntax.h b/source/slang/slang-syntax.h index 35c21227c..c5160e47b 100644 --- a/source/slang/slang-syntax.h +++ b/source/slang/slang-syntax.h @@ -320,8 +320,7 @@ namespace Slang /// ModifiersChecked, - /// The declaration's basic signature has been checked to the point that - /// it is ready to be referenced in other places. + /// The type/signature of the declaration has been checked. /// /// For a value declaration like a variable or function, this means that /// the type of the declaration can be queried. @@ -329,6 +328,15 @@ namespace Slang /// For a type declaration like a `struct` or `typedef` this means /// that a `Type` referring to that declaration can be formed. /// + SignatureChecked, + + /// The declaration's basic signature has been checked to the point that + /// it is ready to be referenced in other places. + /// + /// For a function, this means that it has been organized into a + /// "redeclration group" if there are multiple functions with the + /// same name in a scope. + /// ReadyForReference, /// The declaration is ready for lookup operations to be performed. |
