From 1e5efd82a90b4b677161335a981c8e9846e7148d Mon Sep 17 00:00:00 2001 From: checkraisefold Date: Sun, 27 Oct 2024 18:13:22 -0700 Subject: [PATCH] pre-populate class bindings --- Analysis/src/ConstraintGenerator.cpp | 40 ++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/Analysis/src/ConstraintGenerator.cpp b/Analysis/src/ConstraintGenerator.cpp index e242df8ec..efe4735c2 100644 --- a/Analysis/src/ConstraintGenerator.cpp +++ b/Analysis/src/ConstraintGenerator.cpp @@ -653,6 +653,7 @@ void ConstraintGenerator::applyRefinements(const ScopePtr& scope, Location locat void ConstraintGenerator::checkAliases(const ScopePtr& scope, AstStatBlock* block) { std::unordered_map aliasDefinitionLocations; + std::unordered_map classDefinitionLocations; // In order to enable mutually-recursive type aliases, we need to // populate the type bindings before we actually check any of the @@ -750,6 +751,29 @@ void ConstraintGenerator::checkAliases(const ScopePtr& scope, AstStatBlock* bloc scope->privateTypeBindings[function->name.value] = std::move(typeFunction); aliasDefinitionLocations[function->name.value] = function->location; } + else if (auto classDeclaration = stat->as()) + { + if (scope->exportedTypeBindings.count(classDeclaration->name.value)) + { + auto it = classDefinitionLocations.find(classDeclaration->name.value); + LUAU_ASSERT(it != classDefinitionLocations.end()); + reportError(classDeclaration->location, DuplicateTypeDefinition{classDeclaration->name.value, it->second}); + continue; + } + + // A class might have no name if the code is syntactically + // illegal. We mustn't prepopulate anything in this case. + if (classDeclaration->name == kParseNameError) + continue; + + ScopePtr defnScope = childScope(classDeclaration, scope); + + TypeId initialType = arena->addType(BlockedType{}); + TypeFun initialFun{initialType}; + scope->exportedTypeBindings[classDeclaration->name.value] = std::move(initialFun); + + classDefinitionLocations[classDeclaration->name.value] = classDeclaration->location; + } } } @@ -1645,6 +1669,11 @@ static bool isMetamethod(const Name& name) ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareClass* declaredClass) { + // If a class with the same name was already defined, we skip over + auto bindingIt = scope->exportedTypeBindings.find(declaredClass->name.value); + if (bindingIt == scope->exportedTypeBindings.end()) + return ControlFlow::None; + std::optional superTy = std::make_optional(builtinTypes->classType); if (declaredClass->superName) { @@ -1659,9 +1688,9 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareClas // We don't have generic classes, so this assertion _should_ never be hit. LUAU_ASSERT(lookupType->typeParams.size() == 0 && lookupType->typePackParams.size() == 0); - superTy = lookupType->type; + superTy = follow(lookupType->type); - if (!get(follow(*superTy))) + if (!get(*superTy)) { reportError( declaredClass->location, @@ -1682,7 +1711,8 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareClas ctv->metatable = metaTy; - scope->exportedTypeBindings[className] = TypeFun{{}, classTy}; + TypeId classBindTy = bindingIt->second.type; + emplaceType(asMutable(classBindTy), classTy); if (declaredClass->indexer) { @@ -2913,7 +2943,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr, std::vector toBlock; if (DFInt::LuauTypeSolverRelease >= 648) { - // This logic is incomplete as we want to re-run this + // This logic is incomplete as we want to re-run this // _after_ blocked types have resolved, but this // allows us to do some bidirectional inference. toBlock = findBlockedTypesIn(expr, NotNull{&module->astTypes}); @@ -2931,7 +2961,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr, toBlock ); // The visitor we ran prior should ensure that there are no - // blocked types that we would encounter while matching on + // blocked types that we would encounter while matching on // this expression. LUAU_ASSERT(toBlock.empty()); }