mirror of
https://github.com/luau-lang/luau.git
synced 2025-05-04 10:33:46 +01:00
Add prototype for CTVs
This commit is contained in:
parent
e392aee931
commit
a6b4064be7
2 changed files with 41 additions and 7 deletions
|
@ -95,6 +95,7 @@ struct TypeChecker
|
|||
void check(const ScopePtr& scope, const AstStatDeclareFunction& declaredFunction);
|
||||
|
||||
void prototype(const ScopePtr& scope, const AstStatTypeAlias& typealias, int subLevel = 0);
|
||||
void prototype(const ScopePtr& scope, const AstStatDeclareClass& declaredClass);
|
||||
|
||||
void checkBlock(const ScopePtr& scope, const AstStatBlock& statement);
|
||||
void checkBlockWithoutRecursionCheck(const ScopePtr& scope, const AstStatBlock& statement);
|
||||
|
@ -399,6 +400,11 @@ private:
|
|||
*/
|
||||
DenseHashSet<std::pair<bool, Name>, HashBoolNamePair> duplicateTypeAliases;
|
||||
|
||||
/**
|
||||
* A set of incorrect class definitions which is used to avoid a second-pass analysis.
|
||||
*/
|
||||
DenseHashSet<const AstStatDeclareClass*> incorrectClassDefinitions{nullptr};
|
||||
|
||||
std::vector<std::pair<TypeId, ScopePtr>> deferredQuantification;
|
||||
};
|
||||
|
||||
|
|
|
@ -355,6 +355,7 @@ ModulePtr TypeChecker::checkWithoutRecursionCheck(const SourceModule& module, Mo
|
|||
unifierState.skipCacheForType.clear();
|
||||
|
||||
duplicateTypeAliases.clear();
|
||||
incorrectClassDefinitions.clear();
|
||||
|
||||
return std::move(currentModule);
|
||||
}
|
||||
|
@ -522,6 +523,10 @@ void TypeChecker::checkBlockWithoutRecursionCheck(const ScopePtr& scope, const A
|
|||
prototype(scope, *typealias, subLevel);
|
||||
++subLevel;
|
||||
}
|
||||
else if (const auto& declaredClass = stat->as<AstStatDeclareClass>())
|
||||
{
|
||||
prototype(scope, *declaredClass);
|
||||
}
|
||||
}
|
||||
|
||||
auto protoIter = sorted.begin();
|
||||
|
@ -1626,8 +1631,10 @@ void TypeChecker::prototype(const ScopePtr& scope, const AstStatTypeAlias& typea
|
|||
}
|
||||
}
|
||||
|
||||
void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& declaredClass)
|
||||
void TypeChecker::prototype(const ScopePtr& scope, const AstStatDeclareClass& declaredClass)
|
||||
{
|
||||
Name className(declaredClass.name.value);
|
||||
|
||||
std::optional<TypeId> superTy = std::nullopt;
|
||||
if (declaredClass.superName)
|
||||
{
|
||||
|
@ -1637,6 +1644,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& declar
|
|||
if (!lookupType)
|
||||
{
|
||||
reportError(declaredClass.location, UnknownSymbol{superName, UnknownSymbol::Type});
|
||||
incorrectClassDefinitions.insert(&declaredClass);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1648,22 +1656,42 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& declar
|
|||
{
|
||||
reportError(declaredClass.location,
|
||||
GenericError{format("Cannot use non-class type '%s' as a superclass of class '%s'", superName.c_str(), declaredClass.name.value)});
|
||||
|
||||
incorrectClassDefinitions.insert(&declaredClass);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Name className(declaredClass.name.value);
|
||||
|
||||
TypeId classTy = addType(ClassTypeVar(className, {}, superTy, std::nullopt, {}, {}, currentModuleName));
|
||||
ClassTypeVar* ctv = getMutable<ClassTypeVar>(classTy);
|
||||
|
||||
TypeId metaTy = addType(TableTypeVar{TableState::Sealed, scope->level});
|
||||
TableTypeVar* metatable = getMutable<TableTypeVar>(metaTy);
|
||||
|
||||
ctv->metatable = metaTy;
|
||||
|
||||
scope->exportedTypeBindings[className] = TypeFun{{}, classTy};
|
||||
}
|
||||
|
||||
void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& declaredClass)
|
||||
{
|
||||
Name className(declaredClass.name.value);
|
||||
|
||||
// Don't bother checking if the class definition was incorrect
|
||||
if (incorrectClassDefinitions.find(&declaredClass))
|
||||
return;
|
||||
|
||||
std::optional<TypeFun> binding;
|
||||
if (auto it = scope->exportedTypeBindings.find(className); it != scope->exportedTypeBindings.end())
|
||||
binding = it->second;
|
||||
|
||||
// This class definition must have been `prototype()`d first.
|
||||
if (!binding)
|
||||
ice("Not predeclared");
|
||||
|
||||
TypeId classTy = binding->type;
|
||||
ClassTypeVar* ctv = getMutable<ClassTypeVar>(classTy);
|
||||
|
||||
if (!ctv->metatable)
|
||||
ice("No metatable for declared class");
|
||||
|
||||
TableTypeVar* metatable = getMutable<TableTypeVar>(*ctv->metatable);
|
||||
|
||||
for (const AstDeclaredClassProp& prop : declaredClass.props)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue