summaryrefslogtreecommitdiff
path: root/source/slang/slang-check-decl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-check-decl.cpp')
-rw-r--r--source/slang/slang-check-decl.cpp743
1 files changed, 439 insertions, 304 deletions
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index aa84a057f..b56c3cb07 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -61,7 +61,7 @@ static void validateDynInterfaceUsage(
return;
// validate members inside `dyn interface`
- for (auto m : decl->members)
+ for (auto m : decl->getDirectMemberDecls())
{
if (isAssociatedTypeDecl(m))
{
@@ -154,20 +154,16 @@ static void validateDynInterfaceUseWithInheritanceDecl(
{
// Ensure if we inherit from a `dyn interface` that the parent does not have: opaque
// types, unsized types, non-copyable types
- for (auto m : aggTypeDeclParent->members)
+ for (auto varDecl : aggTypeDeclParent->getDirectMemberDeclsOfType<VarDecl>())
{
- auto varDecl = as<VarDecl>(m);
- if (!varDecl)
- continue;
-
visitor->ensureDecl(varDecl, DeclCheckState::ReadyForLookup);
if (isNonCopyableType(varDecl->getType()))
{
sink->diagnose(
- m,
+ varDecl,
Diagnostics::cannotHaveNonCopyableMemberWhenInheritingDynInterface,
- m,
+ varDecl,
interfaceDecl);
}
@@ -176,15 +172,15 @@ static void validateDynInterfaceUseWithInheritanceDecl(
bool isOpaque = varTypeTags & (int)TypeTag::Opaque;
if (isUnsized)
sink->diagnose(
- m,
+ varDecl,
Diagnostics::cannotHaveUnsizedMemberWhenInheritingDynInterface,
- m,
+ varDecl,
interfaceDecl);
if (isOpaque)
sink->diagnose(
- m,
+ varDecl,
Diagnostics::cannotHaveOpaqueMemberWhenInheritingDynInterface,
- m,
+ varDecl,
interfaceDecl);
}
}
@@ -567,9 +563,9 @@ private:
bool isMemberInitCtor,
Index& paramIndex);
- void synthesizeCtorBodyForMember(
+ void synthesizeCtorBodyForMemberVar(
ConstructorDecl* ctor,
- Decl* member,
+ VarDeclBase* member,
ThisExpr* thisExpr,
Dictionary<Decl*, Expr*>& cachedDeclToCheckedVar,
SeqStmt* seqStmtChild,
@@ -927,7 +923,7 @@ struct SemanticsDeclReferenceVisitor : public SemanticsDeclVisitorBase,
void visitContainerDecl(ContainerDecl* decl)
{
- for (auto m : decl->members)
+ for (auto m : decl->getDirectMemberDecls())
{
dispatchIfNotNull(m);
}
@@ -1545,10 +1541,9 @@ void SemanticsVisitor::ensureAllDeclsRec(Decl* decl, DeclCheckState state)
// takes place, invalidating the iterator and likely a crash.
//
// Accessing the members via index side steps the issue.
- const auto& members = containerDecl->members;
- for (Index i = 0; i < members.getCount(); ++i)
+ for (Index i = 0; i < containerDecl->getDirectMemberDeclCount(); ++i)
{
- Decl* childDecl = members[i];
+ Decl* childDecl = containerDecl->getDirectMemberDecl(i);
// As an exception, if any of the child is a `ScopeDecl`,
// then that indicates that it represents a scope for local
@@ -1710,39 +1705,49 @@ void SemanticsDeclModifiersVisitor::visitStructDecl(StructDecl* structDecl)
// Replace any bitfield member with a property, do this here before
// name lookup to avoid the original var decl being referenced
- for (auto& m : structDecl->members)
+ //
+ auto directMemberDeclCount = structDecl->getDirectMemberDeclCount();
+ for (Index i = 0; i < directMemberDeclCount; ++i)
{
- const auto bfm = m->findModifier<BitFieldModifier>();
- if (!bfm)
+ auto varDecl = as<VarDecl>(structDecl->getDirectMemberDecl(i));
+ if (!varDecl)
continue;
- auto property = m_astBuilder->create<PropertyDecl>();
- property->modifiers = m->modifiers;
- property->type = as<VarDecl>(m)->type;
- property->loc = m->loc;
- property->nameAndLoc = m->getNameAndLoc();
- property->parentDecl = structDecl;
- property->ownedScope = m_astBuilder->create<Scope>();
- property->ownedScope->containerDecl = property;
- property->ownedScope->parent = getScope(structDecl);
- m = property;
-
- const auto get = m_astBuilder->create<GetterDecl>();
- get->ownedScope = m_astBuilder->create<Scope>();
- get->ownedScope->containerDecl = get;
- get->ownedScope->parent = getScope(property);
- property->addMember(get);
-
- const auto set = m_astBuilder->create<SetterDecl>();
- addModifier(set, m_astBuilder->create<MutatingAttribute>());
- set->ownedScope = m_astBuilder->create<Scope>();
- set->ownedScope->containerDecl = set;
- set->ownedScope->parent = getScope(property);
- property->addMember(set);
+ const auto bitFieldModifier = varDecl->findModifier<BitFieldModifier>();
+ if (!bitFieldModifier)
+ continue;
- structDecl->invalidateMemberDictionary();
+ auto propertyDecl = m_astBuilder->create<PropertyDecl>();
+ propertyDecl->modifiers = varDecl->modifiers;
+ propertyDecl->type = varDecl->type;
+ propertyDecl->loc = varDecl->loc;
+ propertyDecl->nameAndLoc = varDecl->getNameAndLoc();
+ propertyDecl->parentDecl = structDecl;
+ propertyDecl->ownedScope = m_astBuilder->create<Scope>();
+ propertyDecl->ownedScope->containerDecl = propertyDecl;
+ propertyDecl->ownedScope->parent = getScope(structDecl);
+
+ auto propertyDeclScope = getScope(propertyDecl);
+
+ const auto getAccessorDecl = m_astBuilder->create<GetterDecl>();
+ getAccessorDecl->ownedScope = m_astBuilder->create<Scope>();
+ getAccessorDecl->ownedScope->containerDecl = getAccessorDecl;
+ getAccessorDecl->ownedScope->parent = propertyDeclScope;
+ propertyDecl->addMember(getAccessorDecl);
+
+ const auto setAccessorDecl = m_astBuilder->create<SetterDecl>();
+ addModifier(setAccessorDecl, m_astBuilder->create<MutatingAttribute>());
+ setAccessorDecl->ownedScope = m_astBuilder->create<Scope>();
+ setAccessorDecl->ownedScope->containerDecl = setAccessorDecl;
+ setAccessorDecl->ownedScope->parent = propertyDeclScope;
+ propertyDecl->addMember(setAccessorDecl);
+
+ structDecl
+ ->_replaceDirectMemberBitFieldVariableDeclAtIndexWithPropertyDeclThatWasSynthesizedForIt(
+ i,
+ varDecl,
+ propertyDecl);
}
- structDecl->buildMemberDictionary();
}
void SemanticsDeclHeaderVisitor::checkDerivativeMemberAttributeParent(
@@ -2368,7 +2373,7 @@ static inline bool _isDefaultCtor(ConstructorDecl* ctor)
// 1. default ctor must have no parameters
// 2. default ctor can have parameters, but all parameters have init expr (Because we won't
// differentiate this case from 2.)
- if (ctor->members.getCount() == 0 || allParamHaveInitExpr(ctor))
+ if (ctor->getDirectMemberDeclCount() == 0 || allParamHaveInitExpr(ctor))
{
return true;
}
@@ -2750,21 +2755,48 @@ void SemanticsDeclBodyVisitor::checkVarDeclCommon(VarDeclBase* varDecl)
bool isUnknownSize = (((int)varTypeTags & unsizedMask) != 0);
if (isUnknownSize)
{
- // Unsized decl must appear as the last member of the struct.
- for (auto memberIdx = parentDecl->members.getCount() - 1; memberIdx >= 0; memberIdx--)
+ // If an unsized variable declaration appears as a member of
+ // an aggregate type (such as a `struct`), then it must be
+ // the *last* non-`static` variable declaration in that type.
+ //
+ // We validate that here by iterating over the members in
+ // reverse order, until we either run into the unsized variable
+ // declaration in question (in which case things are fine),
+ // or we encounter some *other* non-`static` variable declaration,
+ // in which case the unsized declaration is invalid.
+ //
+ for (auto memberIdx = parentDecl->getDirectMemberDeclCount() - 1; memberIdx >= 0;
+ memberIdx--)
{
- if (parentDecl->members[memberIdx] == varDecl)
- {
- break;
- }
- if (auto memberVarDecl = as<VarDeclBase>(parentDecl->members[memberIdx]))
- {
- if (!memberVarDecl->hasModifier<HLSLStaticModifier>())
- {
- getSink()->diagnose(varDecl, Diagnostics::unsizedMemberMustAppearLast);
- }
+ auto memberDecl = parentDecl->getDirectMemberDecl(memberIdx);
+
+ // If we run into the unsized variable declaration before
+ // hitting anything else, the declaration is in a valid
+ // location.
+ //
+ if (memberDecl == varDecl)
break;
- }
+
+ // If we run into another declaration, but it isn't a
+ // variable, then it doesn't impact validity.
+ //
+ auto memberVarDecl = as<VarDeclBase>(memberDecl);
+ if (!memberVarDecl)
+ continue;
+
+ // If we run into another variable declaration, but
+ // it is a `static` variable, then it doesn't
+ // impact the validity of the unsized declaration.
+ //
+ if (memberVarDecl->hasModifier<HLSLStaticModifier>())
+ continue;
+
+ // At this point we've run into a non-`static` variable declaration
+ // that comes *after* the unsized variable declaration, which
+ // means the unsized variable declaration is invalid.
+ //
+ getSink()->diagnose(varDecl, Diagnostics::unsizedMemberMustAppearLast);
+ break;
}
}
}
@@ -2873,11 +2905,10 @@ bool SemanticsVisitor::trySynthesizeDifferentialAssociatedTypeRequirementWitness
RefPtr<WitnessTable> witnessTable)
{
ASTSynthesizer synth(m_astBuilder, getNamePool());
- Decl* existingDecl = nullptr;
+
AggTypeDecl* aggTypeDecl = nullptr;
- if (context->parentDecl->getMemberDictionary().tryGetValue(
- requirementDeclRef.getName(),
- existingDecl))
+ if (auto existingDecl =
+ context->parentDecl->findLastDirectMemberDeclOfName(requirementDeclRef.getName()))
{
// Remove the `ToBeSynthesizedModifier`.
if (as<ToBeSynthesizedModifier>(existingDecl->modifiers.first))
@@ -2942,10 +2973,10 @@ bool SemanticsVisitor::trySynthesizeDifferentialAssociatedTypeRequirementWitness
if (!aggTypeDecl)
{
aggTypeDecl = m_astBuilder->create<StructDecl>();
- context->parentDecl->addMember(aggTypeDecl);
aggTypeDecl->nameAndLoc.name = requirementDeclRef.getName();
aggTypeDecl->loc = context->parentDecl->nameAndLoc.loc;
- context->parentDecl->invalidateMemberDictionary();
+
+ context->parentDecl->addDirectMemberDecl(aggTypeDecl);
synth.pushScopeForContainer(aggTypeDecl);
}
@@ -3000,12 +3031,11 @@ bool SemanticsVisitor::trySynthesizeDifferentialAssociatedTypeRequirementWitness
diffField->nameAndLoc = member->nameAndLoc;
diffField->type.type = diffMemberType;
diffField->checkState = DeclCheckState::SignatureChecked;
- aggTypeDecl->addMember(diffField);
auto visibility = getDeclVisibility(member);
addVisibilityModifier(diffField, visibility);
- aggTypeDecl->invalidateMemberDictionary();
+ aggTypeDecl->addDirectMemberDecl(diffField);
// Inject a `DerivativeMember` modifier on the differential field to point to itself.
{
@@ -3059,25 +3089,17 @@ bool SemanticsVisitor::trySynthesizeDifferentialAssociatedTypeRequirementWitness
}
// The `Differential` type of a `Differential` type is always itself.
- bool hasDifferentialTypeDef = false;
- for (auto member : aggTypeDecl->members)
- {
- if (auto name = member->getName())
- {
- if (name->text == "Differential")
- {
- hasDifferentialTypeDef = true;
- break;
- }
- }
- }
+ auto differentialName = getName("Differential");
+ bool hasDifferentialTypeDef =
+ aggTypeDecl->findLastDirectMemberDeclOfName(differentialName) != nullptr;
if (!hasDifferentialTypeDef)
{
auto assocTypeDef = m_astBuilder->create<TypeDefDecl>();
- assocTypeDef->nameAndLoc.name = getName("Differential");
+ assocTypeDef->nameAndLoc.name = differentialName;
assocTypeDef->type.type = satisfyingType;
- aggTypeDecl->addMember(assocTypeDef);
assocTypeDef->setCheckState(DeclCheckState::DefinitionChecked);
+
+ aggTypeDecl->addDirectMemberDecl(assocTypeDef);
}
// Go through all members and collect their differential types.
@@ -3261,10 +3283,9 @@ void SemanticsDeclHeaderVisitor::visitGenericDecl(GenericDecl* genericDecl)
// Accessing the members via index side steps the issue.
int parameterIndex = 0;
- const auto& members = genericDecl->members;
- for (Index i = 0; i < members.getCount(); ++i)
+ for (Index i = 0; i < genericDecl->getDirectMemberDeclCount(); ++i)
{
- Decl* m = members[i];
+ Decl* m = genericDecl->getDirectMemberDecl(i);
if (auto typeParam = as<GenericTypeParamDeclBase>(m))
{
@@ -3492,7 +3513,7 @@ static void _registerBuiltinDeclsRec(Session* session, Decl* decl)
}
if (auto containerDecl = as<ContainerDecl>(decl))
{
- for (auto childDecl : containerDecl->members)
+ for (auto childDecl : containerDecl->getDirectMemberDecls())
{
if (as<ScopeDecl>(childDecl))
continue;
@@ -3539,7 +3560,7 @@ void discoverExtensionDecls(List<ExtensionDecl*>& decls, Decl* parent)
decls.add(extDecl);
if (auto containerDecl = as<ContainerDecl>(parent))
{
- for (auto child : containerDecl->members)
+ for (auto child : containerDecl->getDirectMemberDecls())
{
discoverExtensionDecls(decls, child);
}
@@ -3570,20 +3591,19 @@ void SemanticsDeclVisitorBase::checkModule(ModuleDecl* moduleDecl)
_registerBuiltinDeclsRec(getSession(), moduleDecl);
}
- if (moduleDecl->members.getCount() > 0)
+ if (auto firstDeclInModule = moduleDecl->getFirstDirectMemberDecl())
{
- auto firstMember = moduleDecl->members[0];
- if (as<ImplementingDecl>(firstMember))
+ if (as<ImplementingDecl>(firstDeclInModule))
{
if (!getShared()->isInLanguageServer())
{
// A primary module file can't start with an "implementing" declaration.
getSink()->diagnose(
- firstMember,
+ firstDeclInModule,
Diagnostics::primaryModuleFileCannotStartWithImplementingDecl);
}
}
- else if (!as<ModuleDeclarationDecl>(firstMember))
+ else if (!as<ModuleDeclarationDecl>(firstDeclInModule))
{
// A primary module file must start with a `module` declaration.
// TODO: this warning is disabled for now to free users from massive change for now.
@@ -3613,9 +3633,9 @@ void SemanticsDeclVisitorBase::checkModule(ModuleDecl* moduleDecl)
// files are parsed.
auto visitIncludeDecls = [&](ContainerDecl* fileDecl)
{
- for (Index i = 0; i < fileDecl->members.getCount(); i++)
+ for (Index i = 0; i < fileDecl->getDirectMemberDeclCount(); i++)
{
- auto decl = fileDecl->members[i];
+ auto decl = fileDecl->getDirectMemberDecl(i);
if (auto includeDecl = as<IncludeDecl>(decl))
{
ensureDecl(includeDecl, DeclCheckState::DefinitionChecked);
@@ -3631,9 +3651,9 @@ void SemanticsDeclVisitorBase::checkModule(ModuleDecl* moduleDecl)
}
};
visitIncludeDecls(moduleDecl);
- for (Index i = 0; i < moduleDecl->members.getCount(); i++)
+ for (Index i = 0; i < moduleDecl->getDirectMemberDeclCount(); i++)
{
- if (auto fileDecl = as<FileDecl>(moduleDecl->members[i]))
+ if (auto fileDecl = as<FileDecl>(moduleDecl->getDirectMemberDecl(i)))
visitIncludeDecls(fileDecl);
}
@@ -4101,8 +4121,8 @@ bool SemanticsVisitor::doesGenericSignatureMatchRequirement(
// satisfying value to have the same number of members for it to be an
// exact match.
//
- auto memberCount = requiredGenericDeclRef.getDecl()->members.getCount();
- if (satisfyingGenericDeclRef.getDecl()->members.getCount() != memberCount)
+ auto memberCount = requiredGenericDeclRef.getDecl()->getDirectMemberDeclCount();
+ if (satisfyingGenericDeclRef.getDecl()->getDirectMemberDeclCount() != memberCount)
return false;
// We then want to check that pairwise members match, in order.
@@ -4595,7 +4615,7 @@ GenericDecl* SemanticsVisitor::synthesizeGenericSignatureForRequirementWitness(
// that reference those parametesr as arguments for the call expresison
// that makes up the body.
//
- for (auto member : requiredMemberDeclRef.getDecl()->members)
+ for (auto member : requiredMemberDeclRef.getDecl()->getDirectMemberDecls())
{
if (auto typeParamDeclBase = as<GenericTypeParamDeclBase>(member))
{
@@ -4670,25 +4690,24 @@ GenericDecl* SemanticsVisitor::synthesizeGenericSignatureForRequirementWitness(
// from the original requirement decl. For example, we can simply apply declref substituion on
// the original type constraint `U:IDerived` to get `UImpl : IDerived`.
//
- for (auto member : requiredMemberDeclRef.getDecl()->members)
+ for (auto constraintDecl :
+ requiredMemberDeclRef.getDecl()->getDirectMemberDeclsOfType<GenericTypeConstraintDecl>())
{
- if (auto constraintDecl = as<GenericTypeConstraintDecl>(member))
- {
- auto synConstraintDecl = m_astBuilder->create<GenericTypeConstraintDecl>();
- synConstraintDecl->nameAndLoc = constraintDecl->getNameAndLoc();
- synConstraintDecl->parentDecl = synGenericDecl;
+ auto synConstraintDecl = m_astBuilder->create<GenericTypeConstraintDecl>();
+ synConstraintDecl->nameAndLoc = constraintDecl->getNameAndLoc();
+ synConstraintDecl->parentDecl = synGenericDecl;
- // For generic constraint Sub : Sup, we need to substitute them with
- // synthesized generic parameters.
- //
- synConstraintDecl->sub = TypeExp((Type*)constraintDecl->sub.type->substitute(
- m_astBuilder,
- SubstitutionSet(partiallySpecializedRequiredGenericDeclRef)));
- synConstraintDecl->sup = TypeExp((Type*)constraintDecl->sup.type->substitute(
- m_astBuilder,
- SubstitutionSet(partiallySpecializedRequiredGenericDeclRef)));
- synGenericDecl->members.add(synConstraintDecl);
- }
+ // For generic constraint Sub : Sup, we need to substitute them with
+ // synthesized generic parameters.
+ //
+ synConstraintDecl->sub = TypeExp((Type*)constraintDecl->sub.type->substitute(
+ m_astBuilder,
+ SubstitutionSet(partiallySpecializedRequiredGenericDeclRef)));
+ synConstraintDecl->sup = TypeExp((Type*)constraintDecl->sup.type->substitute(
+ m_astBuilder,
+ SubstitutionSet(partiallySpecializedRequiredGenericDeclRef)));
+
+ synGenericDecl->addDirectMemberDecl(synConstraintDecl);
}
// Override generic pointer to point to the original generic container.
@@ -5182,7 +5201,7 @@ bool SemanticsVisitor::trySynthesizeMethodRequirementWitness(
{
auto genericAppExpr = m_astBuilder->create<GenericAppExpr>();
genericAppExpr->functionExpr = synBase;
- for (auto member : genericDeclRef->members)
+ for (auto member : genericDeclRef->getDirectMemberDecls())
{
if (auto typeParamDecl = as<GenericTypeParamDeclBase>(member))
{
@@ -5421,48 +5440,44 @@ bool SemanticsVisitor::trySynthesizeConstructorRequirementWitness(
SemanticsDeclBodyVisitor bodyVisitor(withParentFunc(ctorDecl));
bodyVisitor.maybeRegisterDifferentiableType(m_astBuilder, context->conformingType);
- for (auto member : context->parentDecl->members)
+ if (auto varDecl = context->parentDecl->findFirstDirectMemberDeclOfType<VarDeclBase>())
{
- if (auto varDecl = as<VarDeclBase>(member))
- {
- auto varExpr = m_astBuilder->create<VarExpr>();
- varExpr->scope = ctorDecl->ownedScope;
- varExpr->name = varDecl->getName();
- auto checkedVarExpr = CheckTerm(varExpr);
- if (!checkedVarExpr)
- return false;
- if (as<ErrorType>(checkedVarExpr->type.type))
- return false;
- auto assign = m_astBuilder->create<AssignExpr>();
- assign->left = checkedVarExpr;
- auto temp = m_astBuilder->create<InvokeExpr>();
- auto lookupResult = lookUpMember(
- m_astBuilder,
- this,
- ctorName,
- varDecl->type.type,
- ctorDecl->ownedScope,
- LookupMask::Function,
- LookupOptions::IgnoreBaseInterfaces);
- temp->functionExpr = createLookupResultExpr(
- ctorName,
- lookupResult,
- nullptr,
- context->parentDecl->loc,
- nullptr);
- temp->arguments.addRange(synArgs);
- auto resolvedVar = ResolveInvoke(temp);
- if (!resolvedVar)
- return false;
- assign->right = resolvedVar;
- assign->type = m_astBuilder->getVoidType();
- bodyVisitor.maybeRegisterDifferentiableType(m_astBuilder, varDecl->type.type);
+ auto varExpr = m_astBuilder->create<VarExpr>();
+ varExpr->scope = ctorDecl->ownedScope;
+ varExpr->name = varDecl->getName();
+ auto checkedVarExpr = CheckTerm(varExpr);
+ if (!checkedVarExpr)
+ return false;
+ if (as<ErrorType>(checkedVarExpr->type.type))
+ return false;
+ auto assign = m_astBuilder->create<AssignExpr>();
+ assign->left = checkedVarExpr;
+ auto temp = m_astBuilder->create<InvokeExpr>();
+ auto lookupResult = lookUpMember(
+ m_astBuilder,
+ this,
+ ctorName,
+ varDecl->type.type,
+ ctorDecl->ownedScope,
+ LookupMask::Function,
+ LookupOptions::IgnoreBaseInterfaces);
+ temp->functionExpr = createLookupResultExpr(
+ ctorName,
+ lookupResult,
+ nullptr,
+ context->parentDecl->loc,
+ nullptr);
+ temp->arguments.addRange(synArgs);
+ auto resolvedVar = ResolveInvoke(temp);
+ if (!resolvedVar)
+ return false;
+ assign->right = resolvedVar;
+ assign->type = m_astBuilder->getVoidType();
+ bodyVisitor.maybeRegisterDifferentiableType(m_astBuilder, varDecl->type.type);
- auto stmt = m_astBuilder->create<ExpressionStmt>();
- stmt->expression = assign;
- seqStmt->stmts.add(stmt);
- break;
- }
+ auto stmt = m_astBuilder->create<ExpressionStmt>();
+ stmt->expression = assign;
+ seqStmt->stmts.add(stmt);
}
}
else if (synArgs.getCount())
@@ -6656,8 +6671,9 @@ bool SemanticsVisitor::trySynthesizeEnumTypeMethodRequirementWitness(
synFunc->nameAndLoc.loc = synFunc->loc;
// synFunc already has its parent set
SLANG_ASSERT(context->parentDecl == synFunc->parentDecl);
- context->parentDecl->addMember(synFunc);
- context->parentDecl->invalidateMemberDictionary();
+
+ context->parentDecl->addDirectMemberDecl(synFunc);
+
addModifier(synFunc, intrinsicOpModifier);
witnessTable->add(
funcDeclRef.getDecl(),
@@ -6751,15 +6767,12 @@ bool SemanticsVisitor::trySynthesizeDifferentialMethodRequirementWitness(
auto varStmt = synth.emitVarDeclStmt(synFunc->returnType.type, getName("result"));
auto resultVarExpr = synth.emitVarExpr(varStmt, synFunc->returnType.type);
- for (auto member : context->parentDecl->members)
+ for (auto varMember : context->parentDecl->getDirectMemberDeclsOfType<VarDeclBase>())
{
- auto derivativeAttr = member->findModifier<DerivativeMemberAttribute>();
+ auto derivativeAttr = varMember->findModifier<DerivativeMemberAttribute>();
if (!derivativeAttr)
continue;
- auto varMember = as<VarDeclBase>(member);
- if (!varMember)
- continue;
ensureDecl(varMember, DeclCheckState::ReadyForReference);
auto memberType = varMember->getType();
auto diffMemberType = tryGetDifferentialType(m_astBuilder, memberType);
@@ -6841,8 +6854,9 @@ bool SemanticsVisitor::trySynthesizeDifferentialMethodRequirementWitness(
Decl* witnessDecl = synGeneric ? (Decl*)synGeneric : synFunc;
SLANG_ASSERT(context->parentDecl == witnessDecl->parentDecl);
- context->parentDecl->addMember(witnessDecl);
- context->parentDecl->invalidateMemberDictionary();
+
+ context->parentDecl->addDirectMemberDecl(witnessDecl);
+
addModifier(synFunc, m_astBuilder->create<SynthesizedModifier>());
// If `This` is nested inside a generic, we need to form a complete declref type to the
@@ -8230,13 +8244,11 @@ void SemanticsDeclBasesVisitor::visitEnumDecl(EnumDecl* decl)
if (auto enumTypeTypeInterfaceDecl =
as<InterfaceDecl>(enumTypeTypeDeclRefType->getDeclRef().getDecl()))
{
- for (auto memberDecl : enumTypeTypeInterfaceDecl->members)
+ if (auto foundMemberDecl =
+ enumTypeTypeInterfaceDecl->findLastDirectMemberDeclOfName(
+ tagAssociatedTypeName))
{
- if (memberDecl->getName() == tagAssociatedTypeName)
- {
- tagAssociatedTypeDecl = memberDecl;
- break;
- }
+ tagAssociatedTypeDecl = foundMemberDecl;
}
}
}
@@ -8469,7 +8481,7 @@ void SemanticsVisitor::getGenericParams(
List<Decl*>& outParams,
List<GenericTypeConstraintDecl*>& outConstraints)
{
- for (auto dd : decl->members)
+ for (auto dd : decl->getDirectMemberDecls())
{
if (dd == decl->inner)
continue;
@@ -8772,7 +8784,7 @@ List<Val*> getDefaultSubstitutionArgs(
if (astBuilder->m_cachedGenericDefaultArgs.tryGetValue(genericDecl, args))
return args;
- for (auto mm : genericDecl->members)
+ for (auto mm : genericDecl->getDirectMemberDecls())
{
if (auto genericTypeParamDecl = as<GenericTypeParamDecl>(mm))
{
@@ -8801,35 +8813,33 @@ List<Val*> getDefaultSubstitutionArgs(
bool shouldCache = true;
// create default substitution arguments for constraints
- for (auto mm : genericDecl->members)
+ for (auto genericTypeConstraintDecl :
+ genericDecl->getDirectMemberDeclsOfType<GenericTypeConstraintDecl>())
{
- if (auto genericTypeConstraintDecl = as<GenericTypeConstraintDecl>(mm))
+ if (semantics)
+ semantics->ensureDecl(genericTypeConstraintDecl, DeclCheckState::ReadyForReference);
+ auto constraintDeclRef =
+ astBuilder->getDirectDeclRef<GenericTypeConstraintDecl>(genericTypeConstraintDecl);
+ auto supType = getSup(astBuilder, constraintDeclRef);
+ if (!supType)
{
- if (semantics)
- semantics->ensureDecl(genericTypeConstraintDecl, DeclCheckState::ReadyForReference);
- auto constraintDeclRef =
- astBuilder->getDirectDeclRef<GenericTypeConstraintDecl>(genericTypeConstraintDecl);
- auto supType = getSup(astBuilder, constraintDeclRef);
- if (!supType)
- {
- args.add(astBuilder->getErrorType());
- shouldCache = false;
- continue;
- }
- auto witness = astBuilder->getDeclaredSubtypeWitness(
- getSub(astBuilder, constraintDeclRef),
- getSup(astBuilder, constraintDeclRef),
- constraintDeclRef);
- // TODO: this is an ugly hack to prevent crashing.
- // In early stages of compilation witness->sub and witness->sup may not be checked yet.
- // When semanticVisitor is present we have used that to ensure the type is checked.
- // However due to how the code is written we cannot guarantee semanticVisitor is always
- // available here, and if we can't get the checked sup/sub type this subst is incomplete
- // and should not be cached.
- if (!witness->getSub())
- shouldCache = false;
- args.add(witness);
+ args.add(astBuilder->getErrorType());
+ shouldCache = false;
+ continue;
}
+ auto witness = astBuilder->getDeclaredSubtypeWitness(
+ getSub(astBuilder, constraintDeclRef),
+ getSup(astBuilder, constraintDeclRef),
+ constraintDeclRef);
+ // TODO: this is an ugly hack to prevent crashing.
+ // In early stages of compilation witness->sub and witness->sup may not be checked yet.
+ // When semanticVisitor is present we have used that to ensure the type is checked.
+ // However due to how the code is written we cannot guarantee semanticVisitor is always
+ // available here, and if we can't get the checked sup/sub type this subst is incomplete
+ // and should not be cached.
+ if (!witness->getSub())
+ shouldCache = false;
+ args.add(witness);
}
if (shouldCache)
@@ -9219,9 +9229,9 @@ void SemanticsVisitor::checkForRedeclaration(Decl* decl)
// We will now look for other declarations with
// the same name in the same parent/container.
//
- parentDecl->buildMemberDictionary();
- for (auto oldDecl = newDecl->nextInContainerWithSameName; oldDecl;
- oldDecl = oldDecl->nextInContainerWithSameName)
+
+ for (auto oldDecl = parentDecl->getPrevDirectMemberDeclWithSameName(newDecl); oldDecl;
+ oldDecl = parentDecl->getPrevDirectMemberDeclWithSameName(oldDecl))
{
// For each matching declaration, we will check
// whether the redeclaration should be allowed,
@@ -9497,20 +9507,20 @@ AssignExpr* SemanticsDeclBodyVisitor::createMemberAssignmentExpr(
Expr* SemanticsDeclBodyVisitor::createCtorParamExpr(ConstructorDecl* ctor, Index paramIndex)
{
- if (paramIndex < ctor->members.getCount())
- {
- if (auto param = as<ParamDecl>(ctor->members[paramIndex]))
- {
- auto paramType = param->getType();
- auto paramExpr = m_astBuilder->create<VarExpr>();
- paramExpr->scope = ctor->ownedScope;
- paramExpr->declRef = param;
- paramExpr->type = paramType;
- paramExpr->loc = param->loc;
- return paramExpr;
- }
- }
- return nullptr;
+ if (paramIndex >= ctor->getDirectMemberDeclCount())
+ return nullptr;
+
+ auto param = as<ParamDecl>(ctor->getDirectMemberDecl(paramIndex));
+ if (!param)
+ return nullptr;
+
+ auto paramType = param->getType();
+ auto paramExpr = m_astBuilder->create<VarExpr>();
+ paramExpr->scope = ctor->ownedScope;
+ paramExpr->declRef = param;
+ paramExpr->type = paramType;
+ paramExpr->loc = param->loc;
+ return paramExpr;
}
void SemanticsDeclBodyVisitor::synthesizeCtorBodyForBases(
@@ -9581,27 +9591,24 @@ void SemanticsDeclBodyVisitor::synthesizeCtorBodyForBases(
}
}
-void SemanticsDeclBodyVisitor::synthesizeCtorBodyForMember(
+void SemanticsDeclBodyVisitor::synthesizeCtorBodyForMemberVar(
ConstructorDecl* ctor,
- Decl* member,
+ VarDeclBase* varDeclBase,
ThisExpr* thisExpr,
Dictionary<Decl*, Expr*>& cachedDeclToCheckedVar,
SeqStmt* seqStmtChild,
bool isMemberInitCtor,
Index& paramIndex)
{
- auto varDeclBase = as<VarDeclBase>(member);
-
// Static variables are initialized at start of runtime, not inside a constructor
// Once thing to notice is that if a member variable doesn't have name, it must be synthesized
// instead of defined by user, we should not put it into the constructor because it's not a real
// member.
- if (!varDeclBase || varDeclBase->hasModifier<HLSLStaticModifier>() ||
- varDeclBase->getName() == nullptr)
+ if (varDeclBase->hasModifier<HLSLStaticModifier>() || varDeclBase->getName() == nullptr)
return;
Expr* initExpr = nullptr;
- auto structDecl = as<StructDecl>(member->parentDecl);
+ auto structDecl = as<StructDecl>(varDeclBase->parentDecl);
bool useParamList = isMemberInitCtor;
useParamList = isMemberInitCtor && structDecl->m_membersVisibleInCtor.contains(varDeclBase);
@@ -9630,21 +9637,21 @@ void SemanticsDeclBodyVisitor::synthesizeCtorBodyForMember(
}
}
- auto assign = createMemberAssignmentExpr(thisExpr, ctor->ownedScope, member, initExpr);
+ auto assign = createMemberAssignmentExpr(thisExpr, ctor->ownedScope, varDeclBase, initExpr);
if (!assign)
return;
auto stmt = m_astBuilder->create<ExpressionStmt>();
stmt->expression = assign;
- stmt->loc = member->loc;
+ stmt->loc = varDeclBase->loc;
Expr* checkedMemberVarExpr;
- if (cachedDeclToCheckedVar.containsKey(member))
- checkedMemberVarExpr = cachedDeclToCheckedVar[member];
+ if (cachedDeclToCheckedVar.containsKey(varDeclBase))
+ checkedMemberVarExpr = cachedDeclToCheckedVar[varDeclBase];
else
{
checkedMemberVarExpr = CheckTerm(assign->left);
- cachedDeclToCheckedVar.add({member, checkedMemberVarExpr});
+ cachedDeclToCheckedVar.add({varDeclBase, checkedMemberVarExpr});
}
seqStmtChild->stmts.add(stmt);
@@ -9667,29 +9674,25 @@ void SemanticsDeclBodyVisitor::maybeInsertDefaultInitExpr(StructDecl* structDecl
thisExpr->scope = ctor->ownedScope;
thisExpr->type = ctor->returnType.type;
auto seqStmtChild = m_astBuilder->create<SeqStmt>();
- seqStmtChild->stmts.reserve(structDecl->members.getCount());
- for (auto& member : structDecl->members)
+ for (auto varDeclBase : structDecl->getDirectMemberDeclsOfType<VarDeclBase>())
{
- if (auto varDeclBase = as<VarDeclBase>(member))
- {
- if (varDeclBase->hasModifier<HLSLStaticModifier>() ||
- varDeclBase->getName() == nullptr || varDeclBase->initExpr == nullptr)
- continue;
+ if (varDeclBase->hasModifier<HLSLStaticModifier>() ||
+ varDeclBase->getName() == nullptr || varDeclBase->initExpr == nullptr)
+ continue;
- auto assign = createMemberAssignmentExpr(
- thisExpr,
- ctor->ownedScope,
- member,
- varDeclBase->initExpr);
- if (!assign)
- continue;
+ auto assign = createMemberAssignmentExpr(
+ thisExpr,
+ ctor->ownedScope,
+ varDeclBase,
+ varDeclBase->initExpr);
+ if (!assign)
+ continue;
- auto stmt = m_astBuilder->create<ExpressionStmt>();
- stmt->expression = assign;
- stmt->loc = member->loc;
- seqStmtChild->stmts.add(stmt);
- }
+ auto stmt = m_astBuilder->create<ExpressionStmt>();
+ stmt->expression = assign;
+ stmt->loc = varDeclBase->loc;
+ seqStmtChild->stmts.add(stmt);
}
if (seqStmtChild->stmts.getCount() != 0)
{
@@ -9709,8 +9712,6 @@ void SemanticsDeclBodyVisitor::synthesizeCtorBody(
{
auto seqStmt = _ensureCtorBodyIsSeqStmt(m_astBuilder, ctor);
auto seqStmtChild = m_astBuilder->create<SeqStmt>();
- seqStmtChild->stmts.reserve(
- inheritanceDefaultCtorList.getCount() + structDecl->members.getCount());
ThisExpr* thisExpr = m_astBuilder->create<ThisExpr>();
thisExpr->scope = ctor->ownedScope;
@@ -9737,11 +9738,11 @@ void SemanticsDeclBodyVisitor::synthesizeCtorBody(
ioParamIndex);
// Then synthesize the initialization of the other members.
- for (auto& m : structDecl->members)
+ for (auto directMemberVarDecl : structDecl->getDirectMemberDeclsOfType<VarDeclBase>())
{
- synthesizeCtorBodyForMember(
+ synthesizeCtorBodyForMemberVar(
ctor,
- m,
+ directMemberVarDecl,
thisExpr,
cachedDeclToCheckedVar,
seqStmtChild,
@@ -9792,12 +9793,9 @@ void SemanticsDeclBodyVisitor::visitAggTypeDecl(AggTypeDecl* aggTypeDecl)
DeclRefType::create(m_astBuilder, structDecl),
m_astBuilder->getDefaultInitializableType(),
IsSubTypeOptions::None);
- for (auto m : structDecl->members)
+ for (auto varDeclBase : structDecl->getDirectMemberDeclsOfType<VarDeclBase>())
{
- auto varDeclBase = as<VarDeclBase>(m);
- if (!varDeclBase)
- continue;
- ensureDecl(m->getDefaultDeclRef(), DeclCheckState::DefaultConstructorReadyForUse);
+ ensureDecl(varDeclBase->getDefaultDeclRef(), DeclCheckState::DefaultConstructorReadyForUse);
if (!isDefaultInitializableType || varDeclBase->initExpr)
continue;
varDeclBase->initExpr = constructDefaultInitExprForType(this, varDeclBase);
@@ -9811,9 +9809,9 @@ void SemanticsDeclBodyVisitor::visitAggTypeDecl(AggTypeDecl* aggTypeDecl)
auto seqStmt = as<SeqStmt>(as<BlockStmt>(structDeclInfo.defaultCtor->body)->body);
if (seqStmt && seqStmt->stmts.getCount() == 0)
{
- structDecl->members.remove(structDeclInfo.defaultCtor);
- structDecl->invalidateMemberDictionary();
- structDecl->buildMemberDictionary();
+ structDecl
+ ->_removeDirectMemberConstructorDeclBecauseSynthesizedAnotherDefaultConstructorInstead(
+ structDeclInfo.defaultCtor);
}
}
}
@@ -10225,12 +10223,22 @@ error:;
void SemanticsDeclBasesVisitor::_validateExtensionDeclMembers(ExtensionDecl* decl)
{
- for (auto m : decl->members)
+ for (auto ctor : decl->getDirectMemberDeclsOfType<ConstructorDecl>())
{
- auto ctor = as<ConstructorDecl>(m);
- if (!ctor || !ctor->body || ctor->members.getCount() != 0)
+ // Note(tfoley): AFAICT, the logic here is enforcing that an
+ // `extension` declaration cannot introduce a default constructor,
+ // unless it introduces that default constructor without a body.
+ //
+ // If the constructor declaration is without a body, we allow it
+ // here, and if it has a non-zero number of direct member declarations
+ // (which this code is assuming will be equivalent to just the
+ // parameter declarations), we also allow it.
+ //
+ // The underlying rationale
+
+ if (!ctor->body || ctor->getDirectMemberDeclCount() != 0)
continue;
- getSink()->diagnose(m->loc, Diagnostics::invalidMemberTypeInExtension, m->astNodeType);
+ getSink()->diagnose(ctor, Diagnostics::invalidMemberTypeInExtension, ctor->astNodeType);
}
}
@@ -10861,18 +10869,22 @@ String getSimpleModuleName(Name* name)
return String(slice.head(dotPos));
}
-ModuleDeclarationDecl* findExistingModuleDeclarationDecl(ModuleDecl* decl)
+ModuleDeclarationDecl* findExistingModuleDeclarationDecl(ModuleDecl* moduleDecl)
{
- if (decl->members.getCount() == 0)
+ auto firstMemberOfModule = moduleDecl->getFirstDirectMemberDecl();
+ if (!firstMemberOfModule)
return nullptr;
- if (auto rs = as<ModuleDeclarationDecl>(decl->members[0]))
- return rs;
- for (auto fileDecl : decl->getMembersOfType<FileDecl>())
+
+ if (auto found = as<ModuleDeclarationDecl>(firstMemberOfModule))
+ return found;
+
+ for (auto fileDecl : moduleDecl->getMembersOfType<FileDecl>())
{
- if (fileDecl->members.getCount() == 0)
+ auto firstMemberOfFile = fileDecl->getFirstDirectMemberDecl();
+ if (!firstMemberOfFile)
continue;
- if (auto rs = as<ModuleDeclarationDecl>(fileDecl->members[0]))
- return rs;
+ if (auto found = as<ModuleDeclarationDecl>(firstMemberOfFile))
+ return found;
}
return nullptr;
}
@@ -10902,11 +10914,11 @@ void SemanticsDeclHeaderVisitor::visitIncludeDecl(IncludeDecl* decl)
if (!isNew)
return;
- if (fileDecl->members.getCount() == 0)
+ auto firstDeclInFile = fileDecl->getFirstDirectMemberDecl();
+ if (!firstDeclInFile)
return;
- auto firstMember = fileDecl->members[0];
- if (auto moduleDeclaration = as<ModuleDeclarationDecl>(firstMember))
+ if (auto moduleDeclaration = as<ModuleDeclarationDecl>(firstDeclInFile))
{
// We are trying to include a file that defines a module, the user could mean "import"
// instead.
@@ -10920,25 +10932,25 @@ void SemanticsDeclHeaderVisitor::visitIncludeDecl(IncludeDecl* decl)
importFileDeclIntoScope(moduleDecl->ownedScope, fileDecl);
- if (auto implementing = as<ImplementingDecl>(firstMember))
+ if (auto implementing = as<ImplementingDecl>(firstDeclInFile))
{
// The file we are including must be implementing the current module.
auto moduleName = getSimpleModuleName(implementing->moduleNameAndLoc.name);
auto expectedModuleName = moduleDecl->getName();
bool shouldSkipDiagnostic = false;
- if (moduleDecl->members.getCount())
+ if (auto firstDeclInModule = moduleDecl->getFirstDirectMemberDecl())
{
- if (auto moduleDeclarationDecl = as<ModuleDeclarationDecl>(moduleDecl->members[0]))
+ if (auto moduleDeclarationDecl = as<ModuleDeclarationDecl>(firstDeclInModule))
{
expectedModuleName = moduleDeclarationDecl->getName();
}
else if (getShared()->isInLanguageServer())
{
- auto moduleDeclarationDecls = findExistingModuleDeclarationDecl(moduleDecl);
- if (moduleDeclarationDecls)
+ auto existingModuleDeclarationDecl = findExistingModuleDeclarationDecl(moduleDecl);
+ if (existingModuleDeclarationDecl)
{
- expectedModuleName = moduleDeclarationDecls->getName();
+ expectedModuleName = existingModuleDeclarationDecl->getName();
}
else
{
@@ -11020,17 +11032,18 @@ void SemanticsDeclScopeWiringVisitor::visitImplementingDecl(ImplementingDecl* de
if (!isNew)
return;
- if (!fileDecl || fileDecl->members.getCount() == 0)
- {
+ if (!fileDecl)
+ return;
+
+ auto firstDeclInFile = fileDecl->getFirstDirectMemberDecl();
+ if (!firstDeclInFile)
return;
- }
- auto firstMember = fileDecl->members[0];
- if (as<ModuleDeclarationDecl>(firstMember))
+ if (as<ModuleDeclarationDecl>(firstDeclInFile))
{
// We are trying to implement a file that defines a module, this is expected.
}
- else if (as<ImplementingDecl>(firstMember))
+ else if (as<ImplementingDecl>(firstDeclInFile))
{
getSink()->diagnose(
decl->moduleNameAndLoc.loc,
@@ -11118,11 +11131,10 @@ void SemanticsDeclScopeWiringVisitor::visitNamespaceDecl(NamespaceDecl* decl)
for (auto scope = parentScope; scope; scope = scope->nextSibling)
{
auto container = scope->containerDecl;
- auto nsDeclPtr = container->getMemberDictionary().tryGetValue(decl->getName());
- if (!nsDeclPtr)
+ auto nsDecl = container->findLastDirectMemberDeclOfName(decl->getName());
+ if (!nsDecl)
continue;
- auto nsDecl = *nsDeclPtr;
- for (auto ns = nsDecl; ns; ns = ns->nextInContainerWithSameName)
+ for (auto ns = nsDecl; ns; ns = container->getPrevDirectMemberDeclWithSameName(ns))
{
if (ns == decl)
continue;
@@ -11281,7 +11293,7 @@ void SharedSemanticsContext::registerCandidateExtension(
}
bool hasInheritanceMember = false;
bool hasImplicitCastMember = false;
- for (auto member : extDecl->members)
+ for (auto member : extDecl->getDirectMemberDecls())
{
if (as<InheritanceDecl>(member))
{
@@ -11829,6 +11841,95 @@ ContainerDecl* findDeclsLowestCommonAncestor(Decl*& a, Decl*& b)
return a->parentDecl;
}
+static int _compareDeclsInCommonParentByOrderOfDeclaration(
+ ContainerDecl* commonParent,
+ Decl* lhs,
+ Decl* rhs)
+{
+ if (lhs == rhs)
+ return 0;
+
+ SLANG_ASSERT(commonParent);
+ SLANG_ASSERT(lhs);
+ SLANG_ASSERT(rhs);
+ SLANG_ASSERT(lhs->parentDecl == commonParent);
+ SLANG_ASSERT(rhs->parentDecl == commonParent);
+
+ // Without doing some kind of caching on `commonParent` (which
+ // would bloat the storage of every `ContainerDecl` just to
+ // support this one use case), the worst-cast complexity of
+ // this operation is always going to be linear in the number
+ // of declarations in `commonParent`.
+ //
+ // In an attempt to optimize for the common case, we will assume
+ // that one or the other of the declarations is near the beginning
+ // or end of the sequence of children.
+ //
+ Count childCount = commonParent->getDirectMemberDeclCount();
+ Index loIndex = 0;
+ Index hiIndex = childCount - 1;
+ for (;;)
+ {
+ SLANG_ASSERT(loIndex < hiIndex);
+
+ auto loDecl = commonParent->getDirectMemberDecl(loIndex);
+ auto hiDecl = commonParent->getDirectMemberDecl(hiIndex);
+
+ // TODO(tfoley): There is a frustratingly subtle issue lurking
+ // in the Slang codebase, where operations (notably including
+ // the reflection API's `getTypeParameterConstraintType()`)
+ // assume that the a generic with N type parameters will have
+ // N constraints, with one constraint per type parameter,
+ // in a matching order.
+ //
+ // This assumption is fundamentally *not* guaranteed by the
+ // Slang compiler, but it has worked often enough in practice
+ // that code has ended up depending on this behavior.
+ //
+ // The long/short is that the ordering of the comparisons here
+ // (which cases return `-1` vs. `1`) is important for not
+ // breaking at least one Slang test, and may also have consequences
+ // for other code.
+ //
+ // We need to audit all of the code that is looking up constraints
+ // on generic declarations and trying to associate constraints
+ // with specific parameters and... well, in the ideal case *stop*
+ // them from doing so, because it isn't always a reasonable way
+ // to do things (e.g., there are constraints that would be missed
+ // if code only pays attention to constraints that have one of
+ // the generic parameters on their left-hand-side). Given that
+ // we probably can't fully deprecate things like the reflection
+ // API operations that rely on this assumption, we should instead
+ // author an as-correct-as-possible version of things that, given
+ // the index of a generic (type) parameter, collects all of the
+ // (conformance) constraints with that parameter on the left-hand-side
+ // and forms a conjunction of the interfaces on the right-hand-side.
+ //
+ // (Alternatively we could separate the storage of the original
+ // parameters/constraints as they were declared, vs. the canonicalized
+ // constraints, and only have the reflection API access the former)
+
+ if (loDecl == lhs)
+ return 1;
+ if (loDecl == rhs)
+ return -1;
+
+ if (hiDecl == lhs)
+ return -1;
+ if (hiDecl == rhs)
+ return 1;
+
+ loIndex++;
+ hiIndex--;
+
+ if (loIndex >= hiIndex)
+ {
+ SLANG_UNEXPECTED("failed to find lhs or rhs in common parent");
+ UNREACHABLE_RETURN(0);
+ }
+ }
+}
+
int compareDecls(Decl& lhs, Decl& rhs)
{
int res = compareThreeWays(lhs.astNodeType, rhs.astNodeType);
@@ -11836,9 +11937,36 @@ int compareDecls(Decl& lhs, Decl& rhs)
return res;
Decl* lLCAChild = &lhs;
Decl* rLCAChild = &rhs;
+
+ // TODO(tfoley): This logic implements rules that provide very
+ // little stability of generated mangled names, in cases where
+ // declarations might ever get reordered.
+ //
+ // A more flexible solution would favor comparing declarations
+ // by name whenever possible, along the lines of:
+ //
+ // * For each declaration identify it's deepest ancestor that
+ // has a meaningful stable name (anything like a module,
+ // namespace, type, function, etc. and not anything like
+ // a parameter, local declaration, etc.)
+ //
+ // * Compare those deepest ancestors by name lexicographically,
+ // from the root down. If the module names differ, that's
+ // enough to go by. If they are in the same moduel but in
+ // different types, then use that. If one path is a prefix
+ // of the other, then that establishes an ordering.
+ //
+ // * Only if the above wasn't enough to disambiguate things would
+ // we fall back to anthing based on order of declaration, and
+ // even *then* we would probably want to have some safety rails
+ // in place to identify what kinds of declarations are forcing
+ // us down that path, and ensuring that they are kinds of
+ // declarations we explicitly need/want to support here (e.g.,
+ // generic parameters).
+ //
if (ContainerDecl* lca = findDeclsLowestCommonAncestor(lLCAChild, rLCAChild))
{
- res = compareThreeWays(lca->getDeclIndex(lLCAChild), lca->getDeclIndex(rLCAChild));
+ res = _compareDeclsInCommonParentByOrderOfDeclaration(lca, lLCAChild, rLCAChild);
}
else
{
@@ -12078,7 +12206,7 @@ void checkDerivativeAttributeImpl(
auto appExpr = ctx.getASTBuilder()->create<GenericAppExpr>();
Index count = 0;
- for (auto member : genericDecl->members)
+ for (auto member : genericDecl->getDirectMemberDecls())
{
if (as<GenericTypeParamDecl>(member) || as<GenericValueParamDecl>(member) ||
as<GenericTypePackParamDecl>(member))
@@ -13131,7 +13259,8 @@ bool SemanticsDeclAttributesVisitor::_synthesizeCtorSignature(StructDecl* struct
ConstructorDecl* ctor = createCtor(structDecl, ctorVisibility);
ctor->addFlavor(ConstructorDecl::ConstructorFlavor::SynthesizedMemberInit);
- ctor->members.reserve(resultMembers.getCount());
+ List<Decl*> ctorParamsBuiltInReverseOrder;
+ ctorParamsBuiltInReverseOrder.reserve(resultMembers.getCount());
// 2. Add the parameter list
bool stopProcessingDefaultValues = false;
@@ -13163,7 +13292,7 @@ bool SemanticsDeclAttributesVisitor::_synthesizeCtorSignature(StructDecl* struct
ctorParam->nameAndLoc = NameLoc(paramName, ctor->loc);
ctorParam->loc = ctor->loc;
- ctor->members.add(ctorParam);
+ ctorParamsBuiltInReverseOrder.add(ctorParam);
// We need to ensure member is `no_diff` if it cannot be differentiated, `ctor`
// modifiers do not matter in this case since member-wise ctor is always differentiable
@@ -13175,7 +13304,11 @@ bool SemanticsDeclAttributesVisitor::_synthesizeCtorSignature(StructDecl* struct
addModifier(ctorParam, noDiffMod);
}
}
- ctor->members.reverse();
+ ctorParamsBuiltInReverseOrder.reverse();
+ for (auto ctorParam : ctorParamsBuiltInReverseOrder)
+ {
+ ctor->addDirectMemberDecl(ctorParam);
+ }
return true;
}
@@ -13247,20 +13380,22 @@ void SemanticsDeclAttributesVisitor::visitStructDecl(StructDecl* structDecl)
}
const auto backingMemberIndex = groupInfo[0].memberIndex;
- structDecl->members.insert(backingMemberIndex, backingMember);
- structDecl->invalidateMemberDictionary();
+
+ structDecl->_insertDirectMemberDeclAtIndexForBitfieldPropertyBackingMember(
+ backingMemberIndex,
+ backingMember);
+
++memberIndex;
}
- structDecl->buildMemberDictionary();
// Reset everything
backingWidth = 0;
totalWidth = 0;
groupInfo.clear();
};
- for (; memberIndex < structDecl->members.getCount(); ++memberIndex)
+ for (; memberIndex < structDecl->getDirectMemberDeclCount(); ++memberIndex)
{
- const auto& m = structDecl->members[memberIndex];
+ const auto& m = structDecl->getDirectMemberDecl(memberIndex);
// We can trivially skip any non-property decls
const auto v = as<PropertyDecl>(m);
@@ -13737,7 +13872,7 @@ static inline void _dispatchCapabilitiesVisitorOfFunctionDecl(
{
visitor->setParentFuncOfVisitor(funcDecl);
- for (auto member : funcDecl->members)
+ for (auto member : funcDecl->getDirectMemberDecls())
{
visitor->ensureDecl(member, DeclCheckState::CapabilityChecked);
_propagateRequirement(