// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #include "Luau/Constraint.h" #include "Luau/VisitType.h" namespace Luau { Constraint::Constraint(NotNull scope, const Location& location, ConstraintV&& c) : scope(scope) , location(location) , c(std::move(c)) { } struct ReferenceCountInitializer : TypeOnceVisitor { DenseHashSet* result; ReferenceCountInitializer(DenseHashSet* result) : result(result) { } bool visit(TypeId ty, const FreeType&) override { result->insert(ty); return false; } bool visit(TypeId ty, const BlockedType&) override { result->insert(ty); return false; } bool visit(TypeId ty, const PendingExpansionType&) override { result->insert(ty); return false; } bool visit(TypeId ty, const ClassType&) override { // ClassTypes never contain free types. return false; } }; bool isReferenceCountedType(const TypeId typ) { // n.b. this should match whatever `ReferenceCountInitializer` includes. return get(typ) || get(typ) || get(typ); } DenseHashSet Constraint::getMaybeMutatedFreeTypes() const { DenseHashSet types{{}}; ReferenceCountInitializer rci{&types}; if (auto ec = get(*this)) { rci.traverse(ec->resultType); // `EqualityConstraints` should not mutate `assignmentType`. } else if (auto sc = get(*this)) { rci.traverse(sc->subType); rci.traverse(sc->superType); } else if (auto psc = get(*this)) { rci.traverse(psc->subPack); rci.traverse(psc->superPack); } else if (auto gc = get(*this)) { rci.traverse(gc->generalizedType); // `GeneralizationConstraints` should not mutate `sourceType` or `interiorTypes`. } else if (auto itc = get(*this)) { rci.traverse(itc->variables); // `IterableConstraints` should not mutate `iterator`. } else if (auto nc = get(*this)) { rci.traverse(nc->namedType); } else if (auto taec = get(*this)) { rci.traverse(taec->target); } else if (auto ptc = get(*this)) { rci.traverse(ptc->freeType); } else if (auto hpc = get(*this)) { rci.traverse(hpc->resultType); // `HasPropConstraints` should not mutate `subjectType`. } else if (auto spc = get(*this)) { rci.traverse(spc->resultType); // `SetPropConstraints` should not mutate `subjectType` or `propType`. // TODO: is this true? it "unifies" with `propType`, so maybe mutates that one too? } else if (auto hic = get(*this)) { rci.traverse(hic->resultType); // `HasIndexerConstraint` should not mutate `subjectType` or `indexType`. } else if (auto sic = get(*this)) { rci.traverse(sic->propType); // `SetIndexerConstraints` should not mutate `subjectType` or `indexType`. } else if (auto uc = get(*this)) { rci.traverse(uc->resultPack); // `UnpackConstraint` should not mutate `sourcePack`. } else if (auto u1c = get(*this)) { rci.traverse(u1c->resultType); // `Unpack1Constraint` should not mutate `sourceType`. } else if (auto rc = get(*this)) { rci.traverse(rc->ty); } else if (auto rpc = get(*this)) { rci.traverse(rpc->tp); } return types; } } // namespace Luau