From a0b9950541e730dd3095821bb8623c1ba9c09e70 Mon Sep 17 00:00:00 2001
From: Aaron Weiss <aaronweiss@roblox.com>
Date: Fri, 3 Nov 2023 12:47:28 -0700
Subject: [PATCH] Sync to upstream/release/602

---
 ...ntGraphBuilder.h => ConstraintGenerator.h} |  26 +-
 Analysis/include/Luau/DataFlowGraph.h         |   4 +-
 Analysis/include/Luau/Normalize.h             |   3 +-
 Analysis/include/Luau/TypeChecker2.h          |   4 +-
 Analysis/include/Luau/TypeOrPack.h            |  44 ++--
 Analysis/src/Autocomplete.cpp                 |  23 +-
 Analysis/src/BuiltinDefinitions.cpp           |   2 +-
 Analysis/src/Clone.cpp                        |  12 +-
 ...aphBuilder.cpp => ConstraintGenerator.cpp} | 245 ++++++++----------
 Analysis/src/DataFlowGraph.cpp                |  10 +-
 Analysis/src/Frontend.cpp                     |  12 +-
 Analysis/src/Linter.cpp                       |  19 +-
 Analysis/src/Module.cpp                       |   2 +-
 Analysis/src/Normalize.cpp                    | 141 ++++++++--
 Analysis/src/Subtyping.cpp                    |  14 +-
 Analysis/src/TypeChecker2.cpp                 |  47 ++--
 Analysis/src/TypeInfer.cpp                    |  25 +-
 Analysis/src/Unifier.cpp                      |  10 +-
 Ast/include/Luau/Ast.h                        |   1 +
 Ast/include/Luau/Location.h                   |  34 ++-
 Ast/src/Location.cpp                          |  31 ---
 Ast/src/Parser.cpp                            |  36 ++-
 CLI/Compile.cpp                               |  55 +++-
 CodeGen/include/Luau/CodeGen.h                |  24 ++
 CodeGen/include/Luau/IrData.h                 |   4 +
 CodeGen/src/CodeGenLower.h                    |  25 ++
 CodeGen/src/CodeGenUtils.cpp                  |  92 +------
 CodeGen/src/CodeGenUtils.h                    |   1 -
 CodeGen/src/IrDump.cpp                        |   2 +
 CodeGen/src/IrLoweringA64.cpp                 |   7 +
 CodeGen/src/IrLoweringX64.cpp                 |  24 +-
 CodeGen/src/IrTranslateBuiltins.cpp           |  10 +-
 CodeGen/src/IrUtils.cpp                       |   1 +
 CodeGen/src/NativeState.cpp                   |   1 -
 CodeGen/src/NativeState.h                     |   1 -
 CodeGen/src/OptimizeConstProp.cpp             |   1 +
 Compiler/include/Luau/BytecodeBuilder.h       |   2 +
 Compiler/src/BytecodeBuilder.cpp              |   6 +
 Compiler/src/Compiler.cpp                     |  65 +----
 Sources.cmake                                 |   8 +-
 VM/src/lbuiltins.cpp                          |  21 +-
 VM/src/ldo.cpp                                |   4 +-
 bench/tests/sha256.lua                        |   3 +-
 tests/Compiler.test.cpp                       |   9 -
 tests/Conformance.test.cpp                    |   2 -
 ...ure.cpp => ConstraintGeneratorFixture.cpp} |  16 +-
 ...Fixture.h => ConstraintGeneratorFixture.h} |   8 +-
 tests/ConstraintSolver.test.cpp               |   8 +-
 tests/Error.test.cpp                          |   2 +-
 tests/IrBuilder.test.cpp                      |  34 +++
 tests/Linter.test.cpp                         |  71 ++++-
 tests/Module.test.cpp                         |  38 ++-
 tests/Normalize.test.cpp                      |  44 +++-
 tests/Subtyping.test.cpp                      |   9 +
 tests/TypeInfer.aliases.test.cpp              |   6 +-
 tests/TypeInfer.cfa.test.cpp                  |   2 +-
 tests/TypeInfer.classes.test.cpp              |   4 -
 tests/TypeInfer.intersectionTypes.test.cpp    |   2 -
 tests/TypeInfer.oop.test.cpp                  |   2 +-
 tests/TypeInfer.singletons.test.cpp           |   2 -
 tests/TypeInfer.tables.test.cpp               |  34 ++-
 tests/TypeInfer.test.cpp                      |   2 -
 tests/TypeInfer.tryUnify.test.cpp             |  39 ++-
 tests/TypePath.test.cpp                       |   2 -
 tests/conformance/bitwise.lua                 |   5 +
 tests/conformance/math.lua                    |   1 +
 tests/conformance/utf8.lua                    |  69 +++--
 tests/main.cpp                                |  65 +++++
 tools/faillist.txt                            |  17 +-
 69 files changed, 1015 insertions(+), 580 deletions(-)
 rename Analysis/include/Luau/{ConstraintGraphBuilder.h => ConstraintGenerator.h} (94%)
 rename Analysis/src/{ConstraintGraphBuilder.cpp => ConstraintGenerator.cpp} (92%)
 rename tests/{ConstraintGraphBuilderFixture.cpp => ConstraintGeneratorFixture.cpp} (62%)
 rename tests/{ConstraintGraphBuilderFixture.h => ConstraintGeneratorFixture.h} (81%)

diff --git a/Analysis/include/Luau/ConstraintGraphBuilder.h b/Analysis/include/Luau/ConstraintGenerator.h
similarity index 94%
rename from Analysis/include/Luau/ConstraintGraphBuilder.h
rename to Analysis/include/Luau/ConstraintGenerator.h
index bba5ebd9..088ae4c2 100644
--- a/Analysis/include/Luau/ConstraintGraphBuilder.h
+++ b/Analysis/include/Luau/ConstraintGenerator.h
@@ -57,7 +57,7 @@ struct InferencePack
     }
 };
 
-struct ConstraintGraphBuilder
+struct ConstraintGenerator
 {
     // A list of all the scopes in the module. This vector holds ownership of the
     // scope pointers; the scopes themselves borrow pointers to other scopes to
@@ -68,7 +68,7 @@ struct ConstraintGraphBuilder
     NotNull<BuiltinTypes> builtinTypes;
     const NotNull<TypeArena> arena;
     // The root scope of the module we're generating constraints for.
-    // This is null when the CGB is initially constructed.
+    // This is null when the CG is initially constructed.
     Scope* rootScope;
 
     struct InferredBinding
@@ -116,13 +116,13 @@ struct ConstraintGraphBuilder
 
     DcrLogger* logger;
 
-    ConstraintGraphBuilder(ModulePtr module, NotNull<Normalizer> normalizer, NotNull<ModuleResolver> moduleResolver,
+    ConstraintGenerator(ModulePtr module, NotNull<Normalizer> normalizer, NotNull<ModuleResolver> moduleResolver,
         NotNull<BuiltinTypes> builtinTypes, NotNull<InternalErrorReporter> ice, const ScopePtr& globalScope,
         std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope, DcrLogger* logger, NotNull<DataFlowGraph> dfg,
         std::vector<RequireCycle> requireCycles);
 
     /**
-     * The entry point to the ConstraintGraphBuilder. This will construct a set
+     * The entry point to the ConstraintGenerator. This will construct a set
      * of scopes, constraints, and free types that can be solved later.
      * @param block the root block to generate constraints for.
      */
@@ -232,12 +232,16 @@ private:
     Inference check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType);
     std::tuple<TypeId, TypeId, RefinementId> checkBinary(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType);
 
-    std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExpr* expr);
-    std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprLocal* local);
-    std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprGlobal* global);
-    std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprIndexName* indexName);
-    std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprIndexExpr* indexExpr);
-    TypeId updateProperty(const ScopePtr& scope, AstExpr* expr);
+    /**
+     * Generate constraints to assign assignedTy to the expression expr
+     * @returns the type of the expression.  This may or may not be assignedTy itself.
+     */
+    std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExpr* expr, TypeId assignedTy);
+    std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprLocal* local, TypeId assignedTy);
+    std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprGlobal* global, TypeId assignedTy);
+    std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprIndexName* indexName, TypeId assignedTy);
+    std::optional<TypeId> checkLValue(const ScopePtr& scope, AstExprIndexExpr* indexExpr, TypeId assignedTy);
+    TypeId updateProperty(const ScopePtr& scope, AstExpr* expr, TypeId assignedTy);
 
     void updateLValueType(AstExpr* lvalue, TypeId ty);
 
@@ -324,7 +328,7 @@ private:
 
     /** Scan the program for global definitions.
      *
-     * ConstraintGraphBuilder needs to differentiate between globals and accesses to undefined symbols. Doing this "for
+     * ConstraintGenerator needs to differentiate between globals and accesses to undefined symbols. Doing this "for
      * real" in a general way is going to be pretty hard, so we are choosing not to tackle that yet. For now, we do an
      * initial scan of the AST and note what globals are defined.
      */
diff --git a/Analysis/include/Luau/DataFlowGraph.h b/Analysis/include/Luau/DataFlowGraph.h
index 34a0484a..f752f022 100644
--- a/Analysis/include/Luau/DataFlowGraph.h
+++ b/Analysis/include/Luau/DataFlowGraph.h
@@ -34,7 +34,7 @@ struct DataFlowGraph
     DataFlowGraph& operator=(DataFlowGraph&&) = default;
 
     DefId getDef(const AstExpr* expr) const;
-    // Look up for the rvalue breadcrumb for a compound assignment.
+    // Look up for the rvalue def for a compound assignment.
     std::optional<DefId> getRValueDefForCompoundAssign(const AstExpr* expr) const;
 
     DefId getDef(const AstLocal* local) const;
@@ -64,7 +64,7 @@ private:
 
     // Compound assignments are in a weird situation where the local being assigned to is also being used at its
     // previous type implicitly in an rvalue position. This map provides the previous binding.
-    DenseHashMap<const AstExpr*, const Def*> compoundAssignBreadcrumbs{nullptr};
+    DenseHashMap<const AstExpr*, const Def*> compoundAssignDefs{nullptr};
 
     DenseHashMap<const AstExpr*, const RefinementKey*> astRefinementKeys{nullptr};
 
diff --git a/Analysis/include/Luau/Normalize.h b/Analysis/include/Luau/Normalize.h
index ebb80e0f..54a4dc61 100644
--- a/Analysis/include/Luau/Normalize.h
+++ b/Analysis/include/Luau/Normalize.h
@@ -29,7 +29,7 @@ bool isConsistentSubtype(TypePackId subTy, TypePackId superTy, NotNull<Scope> sc
 class TypeIds
 {
 private:
-    std::unordered_set<TypeId> types;
+    DenseHashMap<TypeId, bool> types{nullptr};
     std::vector<TypeId> order;
     std::size_t hash = 0;
 
@@ -277,6 +277,7 @@ struct NormalizedType
     NormalizedType& operator=(NormalizedType&&) = default;
 
     // IsType functions
+    bool isUnknown() const;
     /// Returns true if the type is exactly a number. Behaves like Type::isNumber()
     bool isExactlyNumber() const;
 
diff --git a/Analysis/include/Luau/TypeChecker2.h b/Analysis/include/Luau/TypeChecker2.h
index aeeab0f8..b30cfe01 100644
--- a/Analysis/include/Luau/TypeChecker2.h
+++ b/Analysis/include/Luau/TypeChecker2.h
@@ -2,8 +2,6 @@
 
 #pragma once
 
-#include "Luau/Ast.h"
-#include "Luau/Module.h"
 #include "Luau/NotNull.h"
 
 namespace Luau
@@ -13,6 +11,8 @@ struct BuiltinTypes;
 struct DcrLogger;
 struct TypeCheckLimits;
 struct UnifierSharedState;
+struct SourceModule;
+struct Module;
 
 void check(NotNull<BuiltinTypes> builtinTypes, NotNull<UnifierSharedState> sharedState, NotNull<TypeCheckLimits> limits, DcrLogger* logger,
     const SourceModule& sourceModule, Module* module);
diff --git a/Analysis/include/Luau/TypeOrPack.h b/Analysis/include/Luau/TypeOrPack.h
index 2bdca1df..87001910 100644
--- a/Analysis/include/Luau/TypeOrPack.h
+++ b/Analysis/include/Luau/TypeOrPack.h
@@ -12,32 +12,28 @@ namespace Luau
 
 const void* ptr(TypeOrPack ty);
 
-template<typename T>
-const T* get(TypeOrPack ty)
+template<typename T, typename std::enable_if_t<TypeOrPack::is_part_of_v<T>, bool> = true>
+const T* get(const TypeOrPack& tyOrTp)
 {
-    if constexpr (std::is_same_v<T, TypeId>)
-        return ty.get_if<TypeId>();
-    else if constexpr (std::is_same_v<T, TypePackId>)
-        return ty.get_if<TypePackId>();
-    else if constexpr (TypeVariant::is_part_of_v<T>)
-    {
-        if (auto innerTy = ty.get_if<TypeId>())
-            return get<T>(*innerTy);
-        else
-            return nullptr;
-    }
-    else if constexpr (TypePackVariant::is_part_of_v<T>)
-    {
-        if (auto innerTp = ty.get_if<TypePackId>())
-            return get<T>(*innerTp);
-        else
-            return nullptr;
-    }
+    return tyOrTp.get_if<T>();
+}
+
+template<typename T, typename std::enable_if_t<TypeVariant::is_part_of_v<T>, bool> = true>
+const T* get(const TypeOrPack& tyOrTp)
+{
+    if (const TypeId* ty = get<TypeId>(tyOrTp))
+        return get<T>(*ty);
     else
-    {
-        static_assert(always_false_v<T>, "invalid T to get from TypeOrPack");
-        LUAU_UNREACHABLE();
-    }
+        return nullptr;
+}
+
+template<typename T, typename std::enable_if_t<TypePackVariant::is_part_of_v<T>, bool> = true>
+const T* get(const TypeOrPack& tyOrTp)
+{
+    if (const TypePackId* tp = get<TypePackId>(tyOrTp))
+        return get<T>(*tp);
+    else
+        return nullptr;
 }
 
 TypeOrPack follow(TypeOrPack ty);
diff --git a/Analysis/src/Autocomplete.cpp b/Analysis/src/Autocomplete.cpp
index d73598c7..52cb54e3 100644
--- a/Analysis/src/Autocomplete.cpp
+++ b/Analysis/src/Autocomplete.cpp
@@ -5,6 +5,7 @@
 #include "Luau/BuiltinDefinitions.h"
 #include "Luau/Frontend.h"
 #include "Luau/ToString.h"
+#include "Luau/Subtyping.h"
 #include "Luau/TypeInfer.h"
 #include "Luau/TypePack.h"
 
@@ -12,6 +13,7 @@
 #include <unordered_set>
 #include <utility>
 
+LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution);
 LUAU_FASTFLAG(DebugLuauReadWriteProperties);
 LUAU_FASTFLAG(LuauClipExtraHasEndProps);
 LUAU_FASTFLAGVARIABLE(LuauAutocompleteDoEnd, false);
@@ -143,13 +145,24 @@ static bool checkTypeMatch(TypeId subTy, TypeId superTy, NotNull<Scope> scope, T
     InternalErrorReporter iceReporter;
     UnifierSharedState unifierState(&iceReporter);
     Normalizer normalizer{typeArena, builtinTypes, NotNull{&unifierState}};
-    Unifier unifier(NotNull<Normalizer>{&normalizer}, scope, Location(), Variance::Covariant);
 
-    // Cost of normalization can be too high for autocomplete response time requirements
-    unifier.normalize = false;
-    unifier.checkInhabited = false;
+    if (FFlag::DebugLuauDeferredConstraintResolution)
+    {
+        Subtyping subtyping{builtinTypes, NotNull{typeArena}, NotNull{&normalizer}, NotNull{&iceReporter}, scope};
+
+        return subtyping.isSubtype(subTy, superTy).isSubtype;
+    }
+    else
+    {
+        Unifier unifier(NotNull<Normalizer>{&normalizer}, scope, Location(), Variance::Covariant);
+
+        // Cost of normalization can be too high for autocomplete response time requirements
+        unifier.normalize = false;
+        unifier.checkInhabited = false;
+
+        return unifier.canUnify(subTy, superTy).empty();
+    }
 
-    return unifier.canUnify(subTy, superTy).empty();
 }
 
 static TypeCorrectKind checkTypeCorrectKind(
diff --git a/Analysis/src/BuiltinDefinitions.cpp b/Analysis/src/BuiltinDefinitions.cpp
index b7631460..5ce12873 100644
--- a/Analysis/src/BuiltinDefinitions.cpp
+++ b/Analysis/src/BuiltinDefinitions.cpp
@@ -7,7 +7,7 @@
 #include "Luau/Common.h"
 #include "Luau/ToString.h"
 #include "Luau/ConstraintSolver.h"
-#include "Luau/ConstraintGraphBuilder.h"
+#include "Luau/ConstraintGenerator.h"
 #include "Luau/NotNull.h"
 #include "Luau/TypeInfer.h"
 #include "Luau/TypeFamily.h"
diff --git a/Analysis/src/Clone.cpp b/Analysis/src/Clone.cpp
index 01b0bdfd..a0e76987 100644
--- a/Analysis/src/Clone.cpp
+++ b/Analysis/src/Clone.cpp
@@ -14,7 +14,7 @@ LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution)
 LUAU_FASTINTVARIABLE(LuauTypeCloneRecursionLimit, 300)
 LUAU_FASTFLAGVARIABLE(LuauCloneCyclicUnions, false)
 
-LUAU_FASTFLAGVARIABLE(LuauStacklessTypeClone2, false)
+LUAU_FASTFLAGVARIABLE(LuauStacklessTypeClone3, false)
 LUAU_FASTINTVARIABLE(LuauTypeCloneIterationLimit, 100'000)
 
 namespace Luau
@@ -118,6 +118,8 @@ private:
         ty = follow(ty, FollowOption::DisableLazyTypeThunks);
         if (auto it = types->find(ty); it != types->end())
             return it->second;
+        else if (ty->persistent)
+            return ty;
         return std::nullopt;
     }
 
@@ -126,6 +128,8 @@ private:
         tp = follow(tp);
         if (auto it = packs->find(tp); it != packs->end())
             return it->second;
+        else if (tp->persistent)
+            return tp;
         return std::nullopt;
     }
 
@@ -879,7 +883,7 @@ TypePackId clone(TypePackId tp, TypeArena& dest, CloneState& cloneState)
     if (tp->persistent)
         return tp;
 
-    if (FFlag::LuauStacklessTypeClone2)
+    if (FFlag::LuauStacklessTypeClone3)
     {
         TypeCloner2 cloner{NotNull{&dest}, cloneState.builtinTypes, NotNull{&cloneState.seenTypes}, NotNull{&cloneState.seenTypePacks}};
         return cloner.clone(tp);
@@ -905,7 +909,7 @@ TypeId clone(TypeId typeId, TypeArena& dest, CloneState& cloneState)
     if (typeId->persistent)
         return typeId;
 
-    if (FFlag::LuauStacklessTypeClone2)
+    if (FFlag::LuauStacklessTypeClone3)
     {
         TypeCloner2 cloner{NotNull{&dest}, cloneState.builtinTypes, NotNull{&cloneState.seenTypes}, NotNull{&cloneState.seenTypePacks}};
         return cloner.clone(typeId);
@@ -934,7 +938,7 @@ TypeId clone(TypeId typeId, TypeArena& dest, CloneState& cloneState)
 
 TypeFun clone(const TypeFun& typeFun, TypeArena& dest, CloneState& cloneState)
 {
-    if (FFlag::LuauStacklessTypeClone2)
+    if (FFlag::LuauStacklessTypeClone3)
     {
         TypeCloner2 cloner{NotNull{&dest}, cloneState.builtinTypes, NotNull{&cloneState.seenTypes}, NotNull{&cloneState.seenTypePacks}};
 
diff --git a/Analysis/src/ConstraintGraphBuilder.cpp b/Analysis/src/ConstraintGenerator.cpp
similarity index 92%
rename from Analysis/src/ConstraintGraphBuilder.cpp
rename to Analysis/src/ConstraintGenerator.cpp
index 4f4ff306..e5652549 100644
--- a/Analysis/src/ConstraintGraphBuilder.cpp
+++ b/Analysis/src/ConstraintGenerator.cpp
@@ -1,5 +1,5 @@
 // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
-#include "Luau/ConstraintGraphBuilder.h"
+#include "Luau/ConstraintGenerator.h"
 
 #include "Luau/Ast.h"
 #include "Luau/Def.h"
@@ -126,21 +126,21 @@ struct Checkpoint
     size_t offset;
 };
 
-Checkpoint checkpoint(const ConstraintGraphBuilder* cgb)
+Checkpoint checkpoint(const ConstraintGenerator* cg)
 {
-    return Checkpoint{cgb->constraints.size()};
+    return Checkpoint{cg->constraints.size()};
 }
 
 template<typename F>
-void forEachConstraint(const Checkpoint& start, const Checkpoint& end, const ConstraintGraphBuilder* cgb, F f)
+void forEachConstraint(const Checkpoint& start, const Checkpoint& end, const ConstraintGenerator* cg, F f)
 {
     for (size_t i = start.offset; i < end.offset; ++i)
-        f(cgb->constraints[i]);
+        f(cg->constraints[i]);
 }
 
 } // namespace
 
-ConstraintGraphBuilder::ConstraintGraphBuilder(ModulePtr module, NotNull<Normalizer> normalizer, NotNull<ModuleResolver> moduleResolver,
+ConstraintGenerator::ConstraintGenerator(ModulePtr module, NotNull<Normalizer> normalizer, NotNull<ModuleResolver> moduleResolver,
     NotNull<BuiltinTypes> builtinTypes, NotNull<InternalErrorReporter> ice, const ScopePtr& globalScope,
     std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope, DcrLogger* logger, NotNull<DataFlowGraph> dfg,
     std::vector<RequireCycle> requireCycles)
@@ -160,7 +160,7 @@ ConstraintGraphBuilder::ConstraintGraphBuilder(ModulePtr module, NotNull<Normali
     LUAU_ASSERT(module);
 }
 
-void ConstraintGraphBuilder::visitModuleRoot(AstStatBlock* block)
+void ConstraintGenerator::visitModuleRoot(AstStatBlock* block)
 {
     LUAU_ASSERT(scopes.empty());
     LUAU_ASSERT(rootScope == nullptr);
@@ -181,18 +181,18 @@ void ConstraintGraphBuilder::visitModuleRoot(AstStatBlock* block)
         logger->captureGenerationModule(module);
 }
 
-TypeId ConstraintGraphBuilder::freshType(const ScopePtr& scope)
+TypeId ConstraintGenerator::freshType(const ScopePtr& scope)
 {
     return Luau::freshType(arena, builtinTypes, scope.get());
 }
 
-TypePackId ConstraintGraphBuilder::freshTypePack(const ScopePtr& scope)
+TypePackId ConstraintGenerator::freshTypePack(const ScopePtr& scope)
 {
     FreeTypePack f{scope.get()};
     return arena->addTypePack(TypePackVar{std::move(f)});
 }
 
-ScopePtr ConstraintGraphBuilder::childScope(AstNode* node, const ScopePtr& parent)
+ScopePtr ConstraintGenerator::childScope(AstNode* node, const ScopePtr& parent)
 {
     auto scope = std::make_shared<Scope>(parent);
     scopes.emplace_back(node->location, scope);
@@ -206,17 +206,17 @@ ScopePtr ConstraintGraphBuilder::childScope(AstNode* node, const ScopePtr& paren
     return scope;
 }
 
-NotNull<Constraint> ConstraintGraphBuilder::addConstraint(const ScopePtr& scope, const Location& location, ConstraintV cv)
+NotNull<Constraint> ConstraintGenerator::addConstraint(const ScopePtr& scope, const Location& location, ConstraintV cv)
 {
     return NotNull{constraints.emplace_back(new Constraint{NotNull{scope.get()}, location, std::move(cv)}).get()};
 }
 
-NotNull<Constraint> ConstraintGraphBuilder::addConstraint(const ScopePtr& scope, std::unique_ptr<Constraint> c)
+NotNull<Constraint> ConstraintGenerator::addConstraint(const ScopePtr& scope, std::unique_ptr<Constraint> c)
 {
     return NotNull{constraints.emplace_back(std::move(c)).get()};
 }
 
-void ConstraintGraphBuilder::unionRefinements(const RefinementContext& lhs, const RefinementContext& rhs, RefinementContext& dest, std::vector<ConstraintV>* constraints)
+void ConstraintGenerator::unionRefinements(const RefinementContext& lhs, const RefinementContext& rhs, RefinementContext& dest, std::vector<ConstraintV>* constraints)
 {
     const auto intersect = [&](const std::vector<TypeId>& types) {
         if (1 == types.size())
@@ -252,7 +252,7 @@ void ConstraintGraphBuilder::unionRefinements(const RefinementContext& lhs, cons
     }
 }
 
-void ConstraintGraphBuilder::computeRefinement(const ScopePtr& scope, RefinementId refinement, RefinementContext* refis, bool sense, bool eq, std::vector<ConstraintV>* constraints)
+void ConstraintGenerator::computeRefinement(const ScopePtr& scope, RefinementId refinement, RefinementContext* refis, bool sense, bool eq, std::vector<ConstraintV>* constraints)
 {
     if (!refinement)
         return;
@@ -382,7 +382,7 @@ bool mustDeferIntersection(TypeId ty)
 }
 } // namespace
 
-void ConstraintGraphBuilder::applyRefinements(const ScopePtr& scope, Location location, RefinementId refinement)
+void ConstraintGenerator::applyRefinements(const ScopePtr& scope, Location location, RefinementId refinement)
 {
     if (!refinement)
         return;
@@ -439,7 +439,7 @@ void ConstraintGraphBuilder::applyRefinements(const ScopePtr& scope, Location lo
         addConstraint(scope, location, c);
 }
 
-ControlFlow ConstraintGraphBuilder::visitBlockWithoutChildScope(const ScopePtr& scope, AstStatBlock* block)
+ControlFlow ConstraintGenerator::visitBlockWithoutChildScope(const ScopePtr& scope, AstStatBlock* block)
 {
     RecursionCounter counter{&recursionCount};
 
@@ -502,7 +502,7 @@ ControlFlow ConstraintGraphBuilder::visitBlockWithoutChildScope(const ScopePtr&
     return firstControlFlow.value_or(ControlFlow::None);
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStat* stat)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStat* stat)
 {
     RecursionLimiter limiter{&recursionCount, FInt::LuauCheckRecursionLimit};
 
@@ -560,7 +560,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStat* stat)
     }
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocal* statLocal)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatLocal* statLocal)
 {
     std::vector<std::optional<TypeId>> varTypes;
     varTypes.reserve(statLocal->vars.size);
@@ -663,7 +663,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocal* s
     return ControlFlow::None;
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFor* for_)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatFor* for_)
 {
     TypeId annotationTy = builtinTypes->numberType;
     if (for_->var->annotation)
@@ -693,7 +693,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFor* for
     return ControlFlow::None;
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatForIn* forIn)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatForIn* forIn)
 {
     ScopePtr loopScope = childScope(forIn, scope);
 
@@ -728,7 +728,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatForIn* f
     return ControlFlow::None;
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatWhile* while_)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatWhile* while_)
 {
     RefinementId refinement = check(scope, while_->condition).refinement;
 
@@ -740,7 +740,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatWhile* w
     return ControlFlow::None;
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatRepeat* repeat)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatRepeat* repeat)
 {
     ScopePtr repeatScope = childScope(repeat, scope);
 
@@ -751,7 +751,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatRepeat*
     return ControlFlow::None;
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocalFunction* function)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatLocalFunction* function)
 {
     // Local
     // Global
@@ -801,7 +801,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocalFun
     return ControlFlow::None;
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFunction* function)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatFunction* function)
 {
     // Name could be AstStatLocal, AstStatGlobal, AstStatIndexName.
     // With or without self
@@ -846,7 +846,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFunction
     else if (AstExprIndexName* indexName = function->name->as<AstExprIndexName>())
     {
         Checkpoint check1 = checkpoint(this);
-        std::optional<TypeId> lvalueType = checkLValue(scope, indexName);
+        std::optional<TypeId> lvalueType = checkLValue(scope, indexName, generalizedType);
         LUAU_ASSERT(lvalueType);
         Checkpoint check2 = checkpoint(this);
 
@@ -856,12 +856,9 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFunction
 
         // TODO figure out how to populate the location field of the table Property.
 
-        if (lvalueType)
+        if (lvalueType && *lvalueType != generalizedType)
         {
-            if (get<FreeType>(*lvalueType))
-                asMutable(*lvalueType)->ty.emplace<BoundType>(generalizedType);
-            else
-                addConstraint(scope, indexName->location, SubtypeConstraint{*lvalueType, generalizedType});
+            addConstraint(scope, indexName->location, SubtypeConstraint{*lvalueType, generalizedType});
         }
     }
     else if (AstExprError* err = function->name->as<AstExprError>())
@@ -900,7 +897,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFunction
     return ControlFlow::None;
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatReturn* ret)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatReturn* ret)
 {
     // At this point, the only way scope->returnType should have anything
     // interesting in it is if the function has an explicit return annotation.
@@ -916,7 +913,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatReturn*
     return ControlFlow::Returns;
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatBlock* block)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatBlock* block)
 {
     ScopePtr innerScope = childScope(block, scope);
 
@@ -944,7 +941,7 @@ static void bindFreeType(TypeId a, TypeId b)
         asMutable(b)->ty.emplace<BoundType>(a);
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatAssign* assign)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatAssign* assign)
 {
     std::vector<std::optional<TypeId>> expectedTypes;
     expectedTypes.reserve(assign->vars.size);
@@ -957,16 +954,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatAssign*
         TypeId assignee = arena->addType(BlockedType{});
         assignees.push_back(assignee);
 
-        std::optional<TypeId> upperBound = follow(checkLValue(scope, lvalue));
-        if (upperBound)
-        {
-            if (get<FreeType>(*upperBound))
-                expectedTypes.push_back(std::nullopt);
-            else
-                expectedTypes.push_back(*upperBound);
-
-            addConstraint(scope, lvalue->location, SubtypeConstraint{assignee, *upperBound});
-        }
+        checkLValue(scope, lvalue, assignee);
 
         DefId def = dfg->getDef(lvalue);
         scope->lvalueTypes[def] = assignee;
@@ -979,14 +967,12 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatAssign*
     return ControlFlow::None;
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatCompoundAssign* assign)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatCompoundAssign* assign)
 {
-    std::optional<TypeId> varTy = checkLValue(scope, assign->var);
-
     AstExprBinary binop = AstExprBinary{assign->location, assign->op, assign->var, assign->value};
     TypeId resultTy = check(scope, &binop).ty;
-    if (varTy)
-        addConstraint(scope, assign->location, SubtypeConstraint{resultTy, *varTy});
+
+    checkLValue(scope, assign->var, resultTy);
 
     DefId def = dfg->getDef(assign->var);
     scope->lvalueTypes[def] = resultTy;
@@ -994,7 +980,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatCompound
     return ControlFlow::None;
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatIf* ifStatement)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatIf* ifStatement)
 {
     RefinementId refinement = check(scope, ifStatement->condition, std::nullopt).refinement;
 
@@ -1041,7 +1027,7 @@ static bool occursCheck(TypeId needle, TypeId haystack)
     return false;
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatTypeAlias* alias)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatTypeAlias* alias)
 {
     ScopePtr* defnScope = astTypeAliasDefiningScopes.find(alias);
 
@@ -1090,7 +1076,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatTypeAlia
     return ControlFlow::None;
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareGlobal* global)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareGlobal* global)
 {
     LUAU_ASSERT(global->type);
 
@@ -1115,7 +1101,7 @@ static bool isMetamethod(const Name& name)
            (FFlag::LuauFloorDivision && name == "__idiv");
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareClass* declaredClass)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareClass* declaredClass)
 {
     std::optional<TypeId> superTy = std::make_optional(builtinTypes->classType);
     if (declaredClass->superName)
@@ -1234,7 +1220,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareC
     return ControlFlow::None;
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareFunction* global)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareFunction* global)
 {
     std::vector<std::pair<Name, GenericTypeDefinition>> generics = createGenerics(scope, global->generics);
     std::vector<std::pair<Name, GenericTypePackDefinition>> genericPacks = createGenericPacks(scope, global->genericPacks);
@@ -1279,7 +1265,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareF
     return ControlFlow::None;
 }
 
-ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatError* error)
+ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatError* error)
 {
     for (AstStat* stat : error->statements)
         visit(scope, stat);
@@ -1289,7 +1275,7 @@ ControlFlow ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatError* e
     return ControlFlow::None;
 }
 
-InferencePack ConstraintGraphBuilder::checkPack(
+InferencePack ConstraintGenerator::checkPack(
     const ScopePtr& scope, AstArray<AstExpr*> exprs, const std::vector<std::optional<TypeId>>& expectedTypes)
 {
     std::vector<TypeId> head;
@@ -1320,7 +1306,7 @@ InferencePack ConstraintGraphBuilder::checkPack(
         return InferencePack{arena->addTypePack(TypePack{std::move(head), tail})};
 }
 
-InferencePack ConstraintGraphBuilder::checkPack(
+InferencePack ConstraintGenerator::checkPack(
     const ScopePtr& scope, AstExpr* expr, const std::vector<std::optional<TypeId>>& expectedTypes, bool generalize)
 {
     RecursionCounter counter{&recursionCount};
@@ -1356,7 +1342,7 @@ InferencePack ConstraintGraphBuilder::checkPack(
     return result;
 }
 
-InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCall* call)
+InferencePack ConstraintGenerator::checkPack(const ScopePtr& scope, AstExprCall* call)
 {
     std::vector<AstExpr*> exprArgs;
 
@@ -1530,7 +1516,7 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCa
     }
 }
 
-Inference ConstraintGraphBuilder::check(
+Inference ConstraintGenerator::check(
     const ScopePtr& scope, AstExpr* expr, std::optional<TypeId> expectedType, bool forceSingleton, bool generalize)
 {
     RecursionCounter counter{&recursionCount};
@@ -1600,7 +1586,7 @@ Inference ConstraintGraphBuilder::check(
     return result;
 }
 
-Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprConstantString* string, std::optional<TypeId> expectedType, bool forceSingleton)
+Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprConstantString* string, std::optional<TypeId> expectedType, bool forceSingleton)
 {
     if (forceSingleton)
         return Inference{arena->addType(SingletonType{StringSingleton{std::string{string->value.data, string->value.size}}})};
@@ -1624,7 +1610,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprConstantSt
     return Inference{builtinTypes->stringType};
 }
 
-Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprConstantBool* boolExpr, std::optional<TypeId> expectedType, bool forceSingleton)
+Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprConstantBool* boolExpr, std::optional<TypeId> expectedType, bool forceSingleton)
 {
     const TypeId singletonType = boolExpr->value ? builtinTypes->trueType : builtinTypes->falseType;
     if (forceSingleton)
@@ -1649,7 +1635,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprConstantBo
     return Inference{builtinTypes->booleanType};
 }
 
-Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprLocal* local)
+Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprLocal* local)
 {
     const RefinementKey* key = dfg->getRefinementKey(local);
     std::optional<DefId> rvalueDef = dfg->getRValueDefForCompoundAssign(local);
@@ -1675,10 +1661,10 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprLocal* loc
         return Inference{ty, refinementArena.proposition(key, builtinTypes->truthyType)};
     }
     else
-        ice->ice("CGB: AstExprLocal came before its declaration?");
+        ice->ice("CG: AstExprLocal came before its declaration?");
 }
 
-Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprGlobal* global)
+Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprGlobal* global)
 {
     const RefinementKey* key = dfg->getRefinementKey(global);
     std::optional<DefId> rvalueDef = dfg->getRValueDefForCompoundAssign(global);
@@ -1704,7 +1690,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprGlobal* gl
     }
 }
 
-Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIndexName* indexName)
+Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprIndexName* indexName)
 {
     TypeId obj = check(scope, indexName->expr).ty;
     TypeId result = arena->addType(BlockedType{});
@@ -1726,7 +1712,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIndexName*
         return Inference{result};
 }
 
-Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIndexExpr* indexExpr)
+Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprIndexExpr* indexExpr)
 {
     TypeId obj = check(scope, indexExpr->expr).ty;
     TypeId indexType = check(scope, indexExpr->index).ty;
@@ -1752,7 +1738,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIndexExpr*
         return Inference{result};
 }
 
-Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprFunction* func, std::optional<TypeId> expectedType, bool generalize)
+Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprFunction* func, std::optional<TypeId> expectedType, bool generalize)
 {
     Checkpoint startCheckpoint = checkpoint(this);
     FunctionSignature sig = checkFunctionSignature(scope, func, expectedType);
@@ -1785,7 +1771,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprFunction*
     }
 }
 
-Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprUnary* unary)
+Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprUnary* unary)
 {
     auto [operandType, refinement] = check(scope, unary->expr);
 
@@ -1826,7 +1812,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprUnary* una
     }
 }
 
-Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType)
+Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType)
 {
     auto [leftType, rightType, refinement] = checkBinary(scope, binary, expectedType);
 
@@ -1990,7 +1976,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprBinary* bi
     }
 }
 
-Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIfElse* ifElse, std::optional<TypeId> expectedType)
+Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprIfElse* ifElse, std::optional<TypeId> expectedType)
 {
     ScopePtr condScope = childScope(ifElse->condition, scope);
     RefinementId refinement = check(condScope, ifElse->condition).refinement;
@@ -2006,13 +1992,13 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIfElse* if
     return Inference{expectedType ? *expectedType : simplifyUnion(builtinTypes, arena, thenType, elseType).result};
 }
 
-Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprTypeAssertion* typeAssert)
+Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTypeAssertion* typeAssert)
 {
     check(scope, typeAssert->expr, std::nullopt);
     return Inference{resolveType(scope, typeAssert->annotation, /* inTypeArguments */ false)};
 }
 
-Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprInterpString* interpString)
+Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprInterpString* interpString)
 {
     for (AstExpr* expr : interpString->expressions)
         check(scope, expr);
@@ -2020,7 +2006,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprInterpStri
     return Inference{builtinTypes->stringType};
 }
 
-std::tuple<TypeId, TypeId, RefinementId> ConstraintGraphBuilder::checkBinary(
+std::tuple<TypeId, TypeId, RefinementId> ConstraintGenerator::checkBinary(
     const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType)
 {
     if (binary->op == AstExprBinary::And)
@@ -2133,16 +2119,16 @@ std::tuple<TypeId, TypeId, RefinementId> ConstraintGraphBuilder::checkBinary(
     }
 }
 
-std::optional<TypeId> ConstraintGraphBuilder::checkLValue(const ScopePtr& scope, AstExpr* expr)
+std::optional<TypeId> ConstraintGenerator::checkLValue(const ScopePtr& scope, AstExpr* expr, TypeId assignedTy)
 {
     if (auto local = expr->as<AstExprLocal>())
-        return checkLValue(scope, local);
+        return checkLValue(scope, local, assignedTy);
     else if (auto global = expr->as<AstExprGlobal>())
-        return checkLValue(scope, global);
+        return checkLValue(scope, global, assignedTy);
     else if (auto indexName = expr->as<AstExprIndexName>())
-        return checkLValue(scope, indexName);
+        return checkLValue(scope, indexName, assignedTy);
     else if (auto indexExpr = expr->as<AstExprIndexExpr>())
-        return checkLValue(scope, indexExpr);
+        return checkLValue(scope, indexExpr, assignedTy);
     else if (auto error = expr->as<AstExprError>())
     {
         check(scope, error);
@@ -2152,7 +2138,7 @@ std::optional<TypeId> ConstraintGraphBuilder::checkLValue(const ScopePtr& scope,
         ice->ice("checkLValue is inexhaustive");
 }
 
-std::optional<TypeId> ConstraintGraphBuilder::checkLValue(const ScopePtr& scope, AstExprLocal* local)
+std::optional<TypeId> ConstraintGenerator::checkLValue(const ScopePtr& scope, AstExprLocal* local, TypeId assignedTy)
 {
     /*
      * The caller of this method uses the returned type to emit the proper
@@ -2162,11 +2148,14 @@ std::optional<TypeId> ConstraintGraphBuilder::checkLValue(const ScopePtr& scope,
      * populated by symbols that have type annotations.
      *
      * If this local has an interesting type annotation, it is important that we
-     * return that.
+     * return that and constrain the assigned type.
      */
     std::optional<TypeId> annotatedTy = scope->lookup(local->local);
     if (annotatedTy)
+    {
+        addConstraint(scope, local->location, SubtypeConstraint{assignedTy, *annotatedTy});
         return annotatedTy;
+    }
 
     /*
      * As a safety measure, we'll assert that no type has yet been ascribed to
@@ -2177,34 +2166,19 @@ std::optional<TypeId> ConstraintGraphBuilder::checkLValue(const ScopePtr& scope,
     return std::nullopt;
 }
 
-std::optional<TypeId> ConstraintGraphBuilder::checkLValue(const ScopePtr& scope, AstExprGlobal* global)
+std::optional<TypeId> ConstraintGenerator::checkLValue(const ScopePtr& scope, AstExprGlobal* global, TypeId assignedTy)
 {
     return scope->lookup(Symbol{global->name});
 }
 
-std::optional<TypeId> ConstraintGraphBuilder::checkLValue(const ScopePtr& scope, AstExprIndexName* indexName)
+std::optional<TypeId> ConstraintGenerator::checkLValue(const ScopePtr& scope, AstExprIndexName* indexName, TypeId assignedTy)
 {
-    return updateProperty(scope, indexName);
+    return updateProperty(scope, indexName, assignedTy);
 }
 
-std::optional<TypeId> ConstraintGraphBuilder::checkLValue(const ScopePtr& scope, AstExprIndexExpr* indexExpr)
+std::optional<TypeId> ConstraintGenerator::checkLValue(const ScopePtr& scope, AstExprIndexExpr* indexExpr, TypeId assignedTy)
 {
-    return updateProperty(scope, indexExpr);
-}
-
-static bool isIndexNameEquivalent(AstExpr* expr)
-{
-    if (expr->is<AstExprIndexName>())
-        return true;
-
-    AstExprIndexExpr* e = expr->as<AstExprIndexExpr>();
-    if (e == nullptr)
-        return false;
-
-    if (!e->index->is<AstExprConstantString>())
-        return false;
-
-    return true;
+    return updateProperty(scope, indexExpr, assignedTy);
 }
 
 /**
@@ -2212,8 +2186,19 @@ static bool isIndexNameEquivalent(AstExpr* expr)
  *
  * If expr has the form name.a.b.c
  */
-TypeId ConstraintGraphBuilder::updateProperty(const ScopePtr& scope, AstExpr* expr)
+TypeId ConstraintGenerator::updateProperty(const ScopePtr& scope, AstExpr* expr, TypeId assignedTy)
 {
+    // There are a bunch of cases where we realize that this is not the kind of
+    // assignment that potentially changes the shape of a table.  When we
+    // encounter them, we call this to fall back and do the "usual thing."
+    auto fallback = [&]() {
+        TypeId resTy = check(scope, expr).ty;
+        addConstraint(scope, expr->location, SubtypeConstraint{assignedTy, resTy});
+        return resTy;
+    };
+
+    LUAU_ASSERT(expr->is<AstExprIndexName>() || expr->is<AstExprIndexExpr>());
+
     if (auto indexExpr = expr->as<AstExprIndexExpr>(); indexExpr && !indexExpr->index->is<AstExprConstantString>())
     {
         // An indexer is only interesting in an lvalue-ey way if it is at the
@@ -2231,15 +2216,12 @@ TypeId ConstraintGraphBuilder::updateProperty(const ScopePtr& scope, AstExpr* ex
         TypeId resultType = arena->addType(BlockedType{});
         TypeId subjectType = check(scope, indexExpr->expr).ty;
         TypeId indexType = check(scope, indexExpr->index).ty;
-        TypeId propType = arena->addType(BlockedType{});
-        addConstraint(scope, expr->location, SetIndexerConstraint{resultType, subjectType, indexType, propType});
+        addConstraint(scope, expr->location, SetIndexerConstraint{resultType, subjectType, indexType, assignedTy});
 
-        module->astTypes[expr] = propType;
+        module->astTypes[expr] = assignedTy;
 
-        return propType;
+        return assignedTy;
     }
-    else if (!isIndexNameEquivalent(expr))
-        return check(scope, expr).ty;
 
     Symbol sym;
     const Def* def = nullptr;
@@ -2269,21 +2251,24 @@ TypeId ConstraintGraphBuilder::updateProperty(const ScopePtr& scope, AstExpr* ex
         }
         else if (auto indexExpr = e->as<AstExprIndexExpr>())
         {
-            // We need to populate the type for the index value
-            check(scope, indexExpr->index);
             if (auto strIndex = indexExpr->index->as<AstExprConstantString>())
             {
+                // We need to populate astTypes for the index value.
+                check(scope, indexExpr->index);
+
                 segments.push_back(std::string(strIndex->value.data, strIndex->value.size));
                 exprs.push_back(e);
                 e = indexExpr->expr;
             }
             else
             {
-                return check(scope, expr).ty;
+                return fallback();
             }
         }
         else
-            return check(scope, expr).ty;
+        {
+            return fallback();
+        }
     }
 
     LUAU_ASSERT(!segments.empty());
@@ -2294,16 +2279,14 @@ TypeId ConstraintGraphBuilder::updateProperty(const ScopePtr& scope, AstExpr* ex
     LUAU_ASSERT(def);
     std::optional<std::pair<TypeId, Scope*>> lookupResult = scope->lookupEx(NotNull{def});
     if (!lookupResult)
-        return check(scope, expr).ty;
+        return fallback();
 
     const auto [subjectType, subjectScope] = *lookupResult;
 
-    TypeId propTy = freshType(scope);
-
     std::vector<std::string> segmentStrings(begin(segments), end(segments));
 
     TypeId updatedType = arena->addType(BlockedType{});
-    addConstraint(scope, expr->location, SetPropConstraint{updatedType, subjectType, std::move(segmentStrings), propTy});
+    addConstraint(scope, expr->location, SetPropConstraint{updatedType, subjectType, std::move(segmentStrings), assignedTy});
 
     TypeId prevSegmentTy = updatedType;
     for (size_t i = 0; i < segments.size(); ++i)
@@ -2330,10 +2313,10 @@ TypeId ConstraintGraphBuilder::updateProperty(const ScopePtr& scope, AstExpr* ex
         }
     }
 
-    return propTy;
+    return assignedTy;
 }
 
-void ConstraintGraphBuilder::updateLValueType(AstExpr* lvalue, TypeId ty)
+void ConstraintGenerator::updateLValueType(AstExpr* lvalue, TypeId ty)
 {
     if (auto local = lvalue->as<AstExprLocal>())
     {
@@ -2342,7 +2325,7 @@ void ConstraintGraphBuilder::updateLValueType(AstExpr* lvalue, TypeId ty)
     }
 }
 
-Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType)
+Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType)
 {
     const bool expectedTypeIsFree = expectedType && get<FreeType>(follow(*expectedType));
 
@@ -2462,7 +2445,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprTable* exp
     return Inference{ty};
 }
 
-ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionSignature(
+ConstraintGenerator::FunctionSignature ConstraintGenerator::checkFunctionSignature(
     const ScopePtr& parent, AstExprFunction* fn, std::optional<TypeId> expectedType, std::optional<Location> originalName)
 {
     ScopePtr signatureScope = nullptr;
@@ -2654,7 +2637,7 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS
     };
 }
 
-void ConstraintGraphBuilder::checkFunctionBody(const ScopePtr& scope, AstExprFunction* fn)
+void ConstraintGenerator::checkFunctionBody(const ScopePtr& scope, AstExprFunction* fn)
 {
     visitBlockWithoutChildScope(scope, fn->body);
 
@@ -2662,12 +2645,12 @@ void ConstraintGraphBuilder::checkFunctionBody(const ScopePtr& scope, AstExprFun
 
     if (nullptr != getFallthrough(fn->body))
     {
-        TypePackId empty = arena->addTypePack({}); // TODO we could have CGB retain one of these forever
+        TypePackId empty = arena->addTypePack({}); // TODO we could have CG retain one of these forever
         addConstraint(scope, fn->location, PackSubtypeConstraint{scope->returnType, empty});
     }
 }
 
-TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, bool inTypeArguments, bool replaceErrorWithFresh)
+TypeId ConstraintGenerator::resolveType(const ScopePtr& scope, AstType* ty, bool inTypeArguments, bool replaceErrorWithFresh)
 {
     TypeId result = nullptr;
 
@@ -2895,7 +2878,7 @@ TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, b
     return result;
 }
 
-TypePackId ConstraintGraphBuilder::resolveTypePack(const ScopePtr& scope, AstTypePack* tp, bool inTypeArgument, bool replaceErrorWithFresh)
+TypePackId ConstraintGenerator::resolveTypePack(const ScopePtr& scope, AstTypePack* tp, bool inTypeArgument, bool replaceErrorWithFresh)
 {
     TypePackId result;
     if (auto expl = tp->as<AstTypePackExplicit>())
@@ -2929,7 +2912,7 @@ TypePackId ConstraintGraphBuilder::resolveTypePack(const ScopePtr& scope, AstTyp
     return result;
 }
 
-TypePackId ConstraintGraphBuilder::resolveTypePack(const ScopePtr& scope, const AstTypeList& list, bool inTypeArguments, bool replaceErrorWithFresh)
+TypePackId ConstraintGenerator::resolveTypePack(const ScopePtr& scope, const AstTypeList& list, bool inTypeArguments, bool replaceErrorWithFresh)
 {
     std::vector<TypeId> head;
 
@@ -2947,7 +2930,7 @@ TypePackId ConstraintGraphBuilder::resolveTypePack(const ScopePtr& scope, const
     return arena->addTypePack(TypePack{head, tail});
 }
 
-std::vector<std::pair<Name, GenericTypeDefinition>> ConstraintGraphBuilder::createGenerics(
+std::vector<std::pair<Name, GenericTypeDefinition>> ConstraintGenerator::createGenerics(
     const ScopePtr& scope, AstArray<AstGenericType> generics, bool useCache, bool addTypes)
 {
     std::vector<std::pair<Name, GenericTypeDefinition>> result;
@@ -2977,7 +2960,7 @@ std::vector<std::pair<Name, GenericTypeDefinition>> ConstraintGraphBuilder::crea
     return result;
 }
 
-std::vector<std::pair<Name, GenericTypePackDefinition>> ConstraintGraphBuilder::createGenericPacks(
+std::vector<std::pair<Name, GenericTypePackDefinition>> ConstraintGenerator::createGenericPacks(
     const ScopePtr& scope, AstArray<AstGenericTypePack> generics, bool useCache, bool addTypes)
 {
     std::vector<std::pair<Name, GenericTypePackDefinition>> result;
@@ -3008,7 +2991,7 @@ std::vector<std::pair<Name, GenericTypePackDefinition>> ConstraintGraphBuilder::
     return result;
 }
 
-Inference ConstraintGraphBuilder::flattenPack(const ScopePtr& scope, Location location, InferencePack pack)
+Inference ConstraintGenerator::flattenPack(const ScopePtr& scope, Location location, InferencePack pack)
 {
     const auto& [tp, refinements] = pack;
     RefinementId refinement = nullptr;
@@ -3025,7 +3008,7 @@ Inference ConstraintGraphBuilder::flattenPack(const ScopePtr& scope, Location lo
     return Inference{typeResult, refinement};
 }
 
-void ConstraintGraphBuilder::reportError(Location location, TypeErrorData err)
+void ConstraintGenerator::reportError(Location location, TypeErrorData err)
 {
     errors.push_back(TypeError{location, module->name, std::move(err)});
 
@@ -3033,7 +3016,7 @@ void ConstraintGraphBuilder::reportError(Location location, TypeErrorData err)
         logger->captureGenerationError(errors.back());
 }
 
-void ConstraintGraphBuilder::reportCodeTooComplex(Location location)
+void ConstraintGenerator::reportCodeTooComplex(Location location)
 {
     errors.push_back(TypeError{location, module->name, CodeTooComplex{}});
 
@@ -3069,7 +3052,7 @@ struct GlobalPrepopulator : AstVisitor
     }
 };
 
-void ConstraintGraphBuilder::prepopulateGlobalScope(const ScopePtr& globalScope, AstStatBlock* program)
+void ConstraintGenerator::prepopulateGlobalScope(const ScopePtr& globalScope, AstStatBlock* program)
 {
     GlobalPrepopulator gp{NotNull{globalScope.get()}, arena, dfg};
 
@@ -3079,7 +3062,7 @@ void ConstraintGraphBuilder::prepopulateGlobalScope(const ScopePtr& globalScope,
     program->visit(&gp);
 }
 
-void ConstraintGraphBuilder::fillInInferredBindings(const ScopePtr& globalScope, AstStatBlock* block)
+void ConstraintGenerator::fillInInferredBindings(const ScopePtr& globalScope, AstStatBlock* block)
 {
     for (const auto& [symbol, p] : inferredBindings)
     {
@@ -3094,7 +3077,7 @@ void ConstraintGraphBuilder::fillInInferredBindings(const ScopePtr& globalScope,
     }
 }
 
-std::vector<std::optional<TypeId>> ConstraintGraphBuilder::getExpectedCallTypesForFunctionOverloads(const TypeId fnType)
+std::vector<std::optional<TypeId>> ConstraintGenerator::getExpectedCallTypesForFunctionOverloads(const TypeId fnType)
 {
     std::vector<TypeId> funTys;
     if (auto it = get<IntersectionType>(follow(fnType)))
diff --git a/Analysis/src/DataFlowGraph.cpp b/Analysis/src/DataFlowGraph.cpp
index e3933574..3f78f3a6 100644
--- a/Analysis/src/DataFlowGraph.cpp
+++ b/Analysis/src/DataFlowGraph.cpp
@@ -34,7 +34,7 @@ DefId DataFlowGraph::getDef(const AstExpr* expr) const
 
 std::optional<DefId> DataFlowGraph::getRValueDefForCompoundAssign(const AstExpr* expr) const
 {
-    auto def = compoundAssignBreadcrumbs.find(expr);
+    auto def = compoundAssignDefs.find(expr);
     return def ? std::optional<DefId>(*def) : std::nullopt;
 }
 
@@ -628,11 +628,11 @@ void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExpr* e, DefId incomi
 
 void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprLocal* l, DefId incomingDef, bool isCompoundAssignment)
 {
-    // We need to keep the previous breadcrumb around for a compound assignment.
+    // We need to keep the previous def around for a compound assignment.
     if (isCompoundAssignment)
     {
         if (auto def = scope->lookup(l->local))
-            graph.compoundAssignBreadcrumbs[l] = *def;
+            graph.compoundAssignDefs[l] = *def;
     }
 
     // In order to avoid alias tracking, we need to clip the reference to the parent def.
@@ -643,11 +643,11 @@ void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprLocal* l, DefId i
 
 void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprGlobal* g, DefId incomingDef, bool isCompoundAssignment)
 {
-    // We need to keep the previous breadcrumb around for a compound assignment.
+    // We need to keep the previous def around for a compound assignment.
     if (isCompoundAssignment)
     {
         if (auto def = scope->lookup(g->name))
-            graph.compoundAssignBreadcrumbs[g] = *def;
+            graph.compoundAssignDefs[g] = *def;
     }
 
     // In order to avoid alias tracking, we need to clip the reference to the parent def.
diff --git a/Analysis/src/Frontend.cpp b/Analysis/src/Frontend.cpp
index 6cbc19fa..feea40c4 100644
--- a/Analysis/src/Frontend.cpp
+++ b/Analysis/src/Frontend.cpp
@@ -5,7 +5,7 @@
 #include "Luau/Clone.h"
 #include "Luau/Common.h"
 #include "Luau/Config.h"
-#include "Luau/ConstraintGraphBuilder.h"
+#include "Luau/ConstraintGenerator.h"
 #include "Luau/ConstraintSolver.h"
 #include "Luau/DataFlowGraph.h"
 #include "Luau/DcrLogger.h"
@@ -1255,13 +1255,13 @@ ModulePtr check(const SourceModule& sourceModule, Mode mode, const std::vector<R
 
     Normalizer normalizer{&result->internalTypes, builtinTypes, NotNull{&unifierState}};
 
-    ConstraintGraphBuilder cgb{result, NotNull{&normalizer}, moduleResolver, builtinTypes, iceHandler, parentScope, std::move(prepareModuleScope),
+    ConstraintGenerator cg{result, NotNull{&normalizer}, moduleResolver, builtinTypes, iceHandler, parentScope, std::move(prepareModuleScope),
         logger.get(), NotNull{&dfg}, requireCycles};
 
-    cgb.visitModuleRoot(sourceModule.root);
-    result->errors = std::move(cgb.errors);
+    cg.visitModuleRoot(sourceModule.root);
+    result->errors = std::move(cg.errors);
 
-    ConstraintSolver cs{NotNull{&normalizer}, NotNull(cgb.rootScope), borrowConstraints(cgb.constraints), result->humanReadableName, moduleResolver,
+    ConstraintSolver cs{NotNull{&normalizer}, NotNull(cg.rootScope), borrowConstraints(cg.constraints), result->humanReadableName, moduleResolver,
         requireCycles, logger.get(), limits};
 
     if (options.randomizeConstraintResolutionSeed)
@@ -1283,7 +1283,7 @@ ModulePtr check(const SourceModule& sourceModule, Mode mode, const std::vector<R
     for (TypeError& e : cs.errors)
         result->errors.emplace_back(std::move(e));
 
-    result->scopes = std::move(cgb.scopes);
+    result->scopes = std::move(cg.scopes);
     result->type = sourceModule.type;
 
     result->clonePublicInterface(builtinTypes, *iceHandler);
diff --git a/Analysis/src/Linter.cpp b/Analysis/src/Linter.cpp
index e957eee7..4aef48c3 100644
--- a/Analysis/src/Linter.cpp
+++ b/Analysis/src/Linter.cpp
@@ -14,9 +14,6 @@
 
 LUAU_FASTINTVARIABLE(LuauSuggestionDistance, 4)
 
-LUAU_FASTFLAGVARIABLE(LuauLintDeprecatedFenv, false)
-LUAU_FASTFLAGVARIABLE(LuauLintTableIndexer, false)
-
 namespace Luau
 {
 
@@ -2093,7 +2090,7 @@ private:
         // getfenv/setfenv are deprecated, however they are still used in some test frameworks and don't have a great general replacement
         // for now we warn about the deprecation only when they are used with a numeric first argument; this produces fewer warnings and makes use
         // of getfenv/setfenv a little more localized
-        if (FFlag::LuauLintDeprecatedFenv && !node->self && node->args.size >= 1)
+        if (!node->self && node->args.size >= 1)
         {
             if (AstExprGlobal* fenv = node->func->as<AstExprGlobal>(); fenv && (fenv->name == "getfenv" || fenv->name == "setfenv"))
             {
@@ -2185,7 +2182,7 @@ private:
 
     bool visit(AstExprUnary* node) override
     {
-        if (FFlag::LuauLintTableIndexer && node->op == AstExprUnary::Len)
+        if (node->op == AstExprUnary::Len)
             checkIndexer(node, node->expr, "#");
 
         return true;
@@ -2195,7 +2192,7 @@ private:
     {
         if (AstExprGlobal* func = node->func->as<AstExprGlobal>())
         {
-            if (FFlag::LuauLintTableIndexer && func->name == "ipairs" && node->args.size == 1)
+            if (func->name == "ipairs" && node->args.size == 1)
                 checkIndexer(node, node->args.data[0], "ipairs");
         }
         else if (AstExprIndexName* func = node->func->as<AstExprIndexName>())
@@ -2209,8 +2206,6 @@ private:
 
     void checkIndexer(AstExpr* node, AstExpr* expr, const char* op)
     {
-        LUAU_ASSERT(FFlag::LuauLintTableIndexer);
-
         std::optional<Luau::TypeId> ty = context->getType(expr);
         if (!ty)
             return;
@@ -2653,13 +2648,17 @@ private:
         case ConstantNumberParseResult::Ok:
         case ConstantNumberParseResult::Malformed:
             break;
+        case ConstantNumberParseResult::Imprecise:
+            emitWarning(*context, LintWarning::Code_IntegerParsing, node->location,
+                "Number literal exceeded available precision and was truncated to closest representable number");
+            break;
         case ConstantNumberParseResult::BinOverflow:
             emitWarning(*context, LintWarning::Code_IntegerParsing, node->location,
-                "Binary number literal exceeded available precision and has been truncated to 2^64");
+                "Binary number literal exceeded available precision and was truncated to 2^64");
             break;
         case ConstantNumberParseResult::HexOverflow:
             emitWarning(*context, LintWarning::Code_IntegerParsing, node->location,
-                "Hexadecimal number literal exceeded available precision and has been truncated to 2^64");
+                "Hexadecimal number literal exceeded available precision and was truncated to 2^64");
             break;
         }
 
diff --git a/Analysis/src/Module.cpp b/Analysis/src/Module.cpp
index 580f59f3..d50719a9 100644
--- a/Analysis/src/Module.cpp
+++ b/Analysis/src/Module.cpp
@@ -3,7 +3,7 @@
 
 #include "Luau/Clone.h"
 #include "Luau/Common.h"
-#include "Luau/ConstraintGraphBuilder.h"
+#include "Luau/ConstraintGenerator.h"
 #include "Luau/Normalize.h"
 #include "Luau/RecursionCounter.h"
 #include "Luau/Scope.h"
diff --git a/Analysis/src/Normalize.cpp b/Analysis/src/Normalize.cpp
index 52bbc5d9..c21f7f32 100644
--- a/Analysis/src/Normalize.cpp
+++ b/Analysis/src/Normalize.cpp
@@ -8,7 +8,9 @@
 #include "Luau/Clone.h"
 #include "Luau/Common.h"
 #include "Luau/RecursionCounter.h"
+#include "Luau/Subtyping.h"
 #include "Luau/Type.h"
+#include "Luau/TypeFwd.h"
 #include "Luau/Unifier.h"
 
 LUAU_FASTFLAGVARIABLE(DebugLuauCheckNormalizeInvariant, false)
@@ -19,6 +21,7 @@ LUAU_FASTINTVARIABLE(LuauNormalizeCacheLimit, 100000);
 LUAU_FASTFLAGVARIABLE(LuauNormalizeCyclicUnions, false);
 LUAU_FASTFLAG(LuauTransitiveSubtyping)
 LUAU_FASTFLAG(DebugLuauReadWriteProperties)
+LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution)
 
 namespace Luau
 {
@@ -32,9 +35,14 @@ TypeIds::TypeIds(std::initializer_list<TypeId> tys)
 void TypeIds::insert(TypeId ty)
 {
     ty = follow(ty);
-    auto [_, fresh] = types.insert(ty);
-    if (fresh)
+
+    // get a reference to the slot for `ty` in `types`
+    bool& entry = types[ty];
+
+    // if `ty` is fresh, we can set it to `true`, add it to the order and hash and be done.
+    if (!entry)
     {
+        entry = true;
         order.push_back(ty);
         hash ^= std::hash<TypeId>{}(ty);
     }
@@ -75,25 +83,26 @@ TypeIds::const_iterator TypeIds::end() const
 TypeIds::iterator TypeIds::erase(TypeIds::const_iterator it)
 {
     TypeId ty = *it;
-    types.erase(ty);
+    types[ty] = false;
     hash ^= std::hash<TypeId>{}(ty);
     return order.erase(it);
 }
 
 size_t TypeIds::size() const
 {
-    return types.size();
+    return order.size();
 }
 
 bool TypeIds::empty() const
 {
-    return types.empty();
+    return order.empty();
 }
 
 size_t TypeIds::count(TypeId ty) const
 {
     ty = follow(ty);
-    return types.count(ty);
+    const bool* val = types.find(ty);
+    return (val && *val) ? 1 : 0;
 }
 
 void TypeIds::retain(const TypeIds& there)
@@ -122,7 +131,29 @@ bool TypeIds::isNever() const
 
 bool TypeIds::operator==(const TypeIds& there) const
 {
-    return hash == there.hash && types == there.types;
+    // we can early return if the hashes don't match.
+    if (hash != there.hash)
+        return false;
+
+    // we have to check equality of the sets themselves if not.
+
+    // if the sets are unequal sizes, then they cannot possibly be equal.
+    // it is important to use `order` here and not `types` since the mappings
+    // may have different sizes since removal is not possible, and so erase
+    // simply writes `false` into the map.
+    if (order.size() != there.order.size())
+        return false;
+
+    // otherwise, we'll need to check that every element we have here is in `there`.
+    for (auto ty : order)
+    {
+        // if it's not, we'll return `false`
+        if (there.count(ty) == 0)
+            return false;
+    }
+
+    // otherwise, we've proven the two equal!
+    return true;
 }
 
 NormalizedStringType::NormalizedStringType() {}
@@ -240,6 +271,42 @@ NormalizedType::NormalizedType(NotNull<BuiltinTypes> builtinTypes)
 {
 }
 
+bool NormalizedType::isUnknown() const
+{
+    if (get<UnknownType>(tops))
+        return true;
+
+    // Otherwise, we can still be unknown!
+    bool hasAllPrimitives = isPrim(booleans, PrimitiveType::Boolean) && isPrim(nils, PrimitiveType::NilType) && isNumber(numbers) &&
+                            strings.isString() && isPrim(threads, PrimitiveType::Thread) && isThread(threads);
+
+    // Check is class
+    bool isTopClass = false;
+    for (auto [t, disj] : classes.classes)
+    {
+        if (auto ct = get<ClassType>(t))
+        {
+            if (ct->name == "class" && disj.empty())
+            {
+                isTopClass = true;
+                break;
+            }
+        }
+    }
+    // Check is table
+    bool isTopTable = false;
+    for (auto t : tables)
+    {
+        if (isPrim(t, PrimitiveType::Table))
+        {
+            isTopTable = true;
+            break;
+        }
+    }
+    // any = unknown or error ==> we need to make sure we have all the unknown components, but not errors
+    return get<NeverType>(errors) && hasAllPrimitives && isTopClass && isTopTable && functions.isTop;
+}
+
 bool NormalizedType::isExactlyNumber() const
 {
     return hasNumbers() && !hasTops() && !hasBooleans() && !hasClasses() && !hasErrors() && !hasNils() && !hasStrings() && !hasThreads() &&
@@ -647,8 +714,7 @@ static bool areNormalizedClasses(const NormalizedClassType& tys)
 
 static bool isPlainTyvar(TypeId ty)
 {
-    return (get<FreeType>(ty) || get<GenericType>(ty) || get<BlockedType>(ty) ||
-            get<PendingExpansionType>(ty) || get<TypeFamilyInstanceType>(ty));
+    return (get<FreeType>(ty) || get<GenericType>(ty) || get<BlockedType>(ty) || get<PendingExpansionType>(ty) || get<TypeFamilyInstanceType>(ty));
 }
 
 static bool isNormalizedTyvar(const NormalizedTyvars& tyvars)
@@ -711,6 +777,11 @@ const NormalizedType* Normalizer::normalize(TypeId ty)
     std::unordered_set<TypeId> seenSetTypes;
     if (!unionNormalWithTy(norm, ty, seenSetTypes))
         return nullptr;
+    if (norm.isUnknown())
+    {
+        clearNormal(norm);
+        norm.tops = builtinTypes->unknownType;
+    }
     std::unique_ptr<NormalizedType> uniq = std::make_unique<NormalizedType>(std::move(norm));
     const NormalizedType* result = uniq.get();
     cachedNormals[ty] = std::move(uniq);
@@ -1520,8 +1591,8 @@ bool Normalizer::unionNormalWithTy(NormalizedType& here, TypeId there, std::unor
     }
     else if (FFlag::LuauTransitiveSubtyping && get<UnknownType>(here.tops))
         return true;
-    else if (get<GenericType>(there) || get<FreeType>(there) || get<BlockedType>(there) ||
-             get<PendingExpansionType>(there) || get<TypeFamilyInstanceType>(there))
+    else if (get<GenericType>(there) || get<FreeType>(there) || get<BlockedType>(there) || get<PendingExpansionType>(there) ||
+             get<TypeFamilyInstanceType>(there))
     {
         if (tyvarIndex(there) <= ignoreSmallerTyvars)
             return true;
@@ -2661,8 +2732,8 @@ bool Normalizer::intersectNormalWithTy(NormalizedType& here, TypeId there, std::
                 return false;
         return true;
     }
-    else if (get<GenericType>(there) || get<FreeType>(there) || get<BlockedType>(there) ||
-             get<PendingExpansionType>(there) || get<TypeFamilyInstanceType>(there))
+    else if (get<GenericType>(there) || get<FreeType>(there) || get<BlockedType>(there) || get<PendingExpansionType>(there) ||
+             get<TypeFamilyInstanceType>(there))
     {
         NormalizedType thereNorm{builtinTypes};
         NormalizedType topNorm{builtinTypes};
@@ -2915,32 +2986,58 @@ TypeId Normalizer::typeFromNormal(const NormalizedType& norm)
 
 bool isSubtype(TypeId subTy, TypeId superTy, NotNull<Scope> scope, NotNull<BuiltinTypes> builtinTypes, InternalErrorReporter& ice)
 {
-    if (!FFlag::LuauTransitiveSubtyping)
+    if (!FFlag::LuauTransitiveSubtyping && !FFlag::DebugLuauDeferredConstraintResolution)
         return isConsistentSubtype(subTy, superTy, scope, builtinTypes, ice);
+
     UnifierSharedState sharedState{&ice};
     TypeArena arena;
     Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}};
-    Unifier u{NotNull{&normalizer}, scope, Location{}, Covariant};
 
-    u.tryUnify(subTy, superTy);
-    return !u.failure;
+    // Subtyping under DCR is not implemented using unification!
+    if (FFlag::DebugLuauDeferredConstraintResolution)
+    {
+        Subtyping subtyping{builtinTypes, NotNull{&arena}, NotNull{&normalizer}, NotNull{&ice}, scope};
+
+        return subtyping.isSubtype(subTy, superTy).isSubtype;
+    }
+    else
+    {
+        Unifier u{NotNull{&normalizer}, scope, Location{}, Covariant};
+
+        u.tryUnify(subTy, superTy);
+        return !u.failure;
+    }
 }
 
 bool isSubtype(TypePackId subPack, TypePackId superPack, NotNull<Scope> scope, NotNull<BuiltinTypes> builtinTypes, InternalErrorReporter& ice)
 {
-    if (!FFlag::LuauTransitiveSubtyping)
+    if (!FFlag::LuauTransitiveSubtyping && !FFlag::DebugLuauDeferredConstraintResolution)
         return isConsistentSubtype(subPack, superPack, scope, builtinTypes, ice);
+
     UnifierSharedState sharedState{&ice};
     TypeArena arena;
     Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}};
-    Unifier u{NotNull{&normalizer}, scope, Location{}, Covariant};
 
-    u.tryUnify(subPack, superPack);
-    return !u.failure;
+    // Subtyping under DCR is not implemented using unification!
+    if (FFlag::DebugLuauDeferredConstraintResolution)
+    {
+        Subtyping subtyping{builtinTypes, NotNull{&arena}, NotNull{&normalizer}, NotNull{&ice}, scope};
+
+        return subtyping.isSubtype(subPack, superPack).isSubtype;
+    }
+    else
+    {
+        Unifier u{NotNull{&normalizer}, scope, Location{}, Covariant};
+
+        u.tryUnify(subPack, superPack);
+        return !u.failure;
+    }
 }
 
 bool isConsistentSubtype(TypeId subTy, TypeId superTy, NotNull<Scope> scope, NotNull<BuiltinTypes> builtinTypes, InternalErrorReporter& ice)
 {
+    LUAU_ASSERT(!FFlag::DebugLuauDeferredConstraintResolution);
+
     UnifierSharedState sharedState{&ice};
     TypeArena arena;
     Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}};
@@ -2954,6 +3051,8 @@ bool isConsistentSubtype(TypeId subTy, TypeId superTy, NotNull<Scope> scope, Not
 bool isConsistentSubtype(
     TypePackId subPack, TypePackId superPack, NotNull<Scope> scope, NotNull<BuiltinTypes> builtinTypes, InternalErrorReporter& ice)
 {
+    LUAU_ASSERT(!FFlag::DebugLuauDeferredConstraintResolution);
+
     UnifierSharedState sharedState{&ice};
     TypeArena arena;
     Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}};
diff --git a/Analysis/src/Subtyping.cpp b/Analysis/src/Subtyping.cpp
index e386bf7b..6e386e68 100644
--- a/Analysis/src/Subtyping.cpp
+++ b/Analysis/src/Subtyping.cpp
@@ -321,14 +321,26 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
     if (auto subUnion = get<UnionType>(subTy))
         result = isCovariantWith(env, subUnion, superTy);
     else if (auto superUnion = get<UnionType>(superTy))
+    {
         result = isCovariantWith(env, subTy, superUnion);
+        if (!result.isSubtype && !result.isErrorSuppressing && !result.normalizationTooComplex)
+        {
+            SubtypingResult semantic = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy));
+            if (semantic.isSubtype)
+                result = semantic;
+        }
+    }
     else if (auto superIntersection = get<IntersectionType>(superTy))
         result = isCovariantWith(env, subTy, superIntersection);
     else if (auto subIntersection = get<IntersectionType>(subTy))
     {
         result = isCovariantWith(env, subIntersection, superTy);
         if (!result.isSubtype && !result.isErrorSuppressing && !result.normalizationTooComplex)
-            result = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy));
+        {
+            SubtypingResult semantic = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy));
+            if (semantic.isSubtype)
+                result = semantic;
+        }
     }
     else if (get<AnyType>(superTy))
         result = {true};
diff --git a/Analysis/src/TypeChecker2.cpp b/Analysis/src/TypeChecker2.cpp
index bf8e362d..bd637453 100644
--- a/Analysis/src/TypeChecker2.cpp
+++ b/Analysis/src/TypeChecker2.cpp
@@ -2413,6 +2413,31 @@ struct TypeChecker2
         }
     }
 
+    void explainError(TypeId subTy, TypeId superTy, Location location, const SubtypingResult& r)
+    {
+        if (!r.reasoning)
+            return reportError(TypeMismatch{superTy, subTy}, location);
+
+        std::optional<TypeOrPack> subLeaf = traverse(subTy, r.reasoning->subPath, builtinTypes);
+        std::optional<TypeOrPack> superLeaf = traverse(superTy, r.reasoning->superPath, builtinTypes);
+
+        if (!subLeaf || !superLeaf)
+            ice->ice("Subtyping test returned a reasoning with an invalid path", location);
+
+        if (!get2<TypeId, TypeId>(*subLeaf, *superLeaf) && !get2<TypePackId, TypePackId>(*subLeaf, *superLeaf))
+            ice->ice("Subtyping test returned a reasoning where one path ends at a type and the other ends at a pack.", location);
+
+        std::string reason;
+
+        if (r.reasoning->subPath == r.reasoning->superPath)
+            reason = "at " + toString(r.reasoning->subPath) + ", " + toString(*subLeaf) + " is not a subtype of " + toString(*superLeaf);
+        else
+            reason = "type " + toString(subTy) + toString(r.reasoning->subPath) + " (" + toString(*subLeaf) + ") is not a subtype of " +
+                     toString(superTy) + toString(r.reasoning->superPath) + " (" + toString(*superLeaf) + ")";
+
+        reportError(TypeMismatch{superTy, subTy, reason}, location);
+    }
+
     bool testIsSubtype(TypeId subTy, TypeId superTy, Location location)
     {
         SubtypingResult r = subtyping->isSubtype(subTy, superTy);
@@ -2421,27 +2446,7 @@ struct TypeChecker2
             reportError(NormalizationTooComplex{}, location);
 
         if (!r.isSubtype && !r.isErrorSuppressing)
-        {
-            if (r.reasoning)
-            {
-                std::optional<TypeOrPack> subLeaf = traverse(subTy, r.reasoning->subPath, builtinTypes);
-                std::optional<TypeOrPack> superLeaf = traverse(superTy, r.reasoning->superPath, builtinTypes);
-
-                if (!subLeaf || !superLeaf)
-                    ice->ice("Subtyping test returned a reasoning with an invalid path", location);
-
-                if (!get2<TypeId, TypeId>(*subLeaf, *superLeaf) && !get2<TypePackId, TypePackId>(*subLeaf, *superLeaf))
-                    ice->ice("Subtyping test returned a reasoning where one path ends at a type and the other ends at a pack.", location);
-
-                std::string reason = "type " + toString(subTy) + toString(r.reasoning->subPath) + " (" + toString(*subLeaf) +
-                                     ") is not a subtype of " + toString(superTy) + toString(r.reasoning->superPath) + " (" + toString(*superLeaf) +
-                                     ")";
-
-                reportError(TypeMismatch{superTy, subTy, reason}, location);
-            }
-            else
-                reportError(TypeMismatch{superTy, subTy}, location);
-        }
+            explainError(subTy, superTy, location, r);
 
         return r.isSubtype;
     }
diff --git a/Analysis/src/TypeInfer.cpp b/Analysis/src/TypeInfer.cpp
index a29b1e06..a4734dbd 100644
--- a/Analysis/src/TypeInfer.cpp
+++ b/Analysis/src/TypeInfer.cpp
@@ -35,11 +35,9 @@ LUAU_FASTFLAG(LuauKnowsTheDataModel3)
 LUAU_FASTFLAGVARIABLE(DebugLuauFreezeDuringUnification, false)
 LUAU_FASTFLAGVARIABLE(DebugLuauSharedSelf, false)
 LUAU_FASTFLAG(LuauInstantiateInSubtyping)
-LUAU_FASTFLAGVARIABLE(LuauAllowIndexClassParameters, false)
 LUAU_FASTFLAG(LuauOccursIsntAlwaysFailure)
 LUAU_FASTFLAGVARIABLE(LuauTinyControlFlowAnalysis, false)
 LUAU_FASTFLAGVARIABLE(LuauLoopControlFlowAnalysis, false)
-LUAU_FASTFLAGVARIABLE(LuauVariadicOverloadFix, false)
 LUAU_FASTFLAGVARIABLE(LuauAlwaysCommitInferencesOfFunctionCalls, false)
 LUAU_FASTFLAG(LuauParseDeclareClassIndexer)
 LUAU_FASTFLAG(LuauFloorDivision);
@@ -3412,15 +3410,12 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex
             }
         }
 
-        if (FFlag::LuauAllowIndexClassParameters)
+        if (const ClassType* exprClass = get<ClassType>(exprType))
         {
-            if (const ClassType* exprClass = get<ClassType>(exprType))
-            {
-                if (isNonstrictMode())
-                    return unknownType;
-                reportError(TypeError{expr.location, DynamicPropertyLookupOnClassesUnsafe{exprType}});
-                return errorRecoveryType(scope);
-            }
+            if (isNonstrictMode())
+                return unknownType;
+            reportError(TypeError{expr.location, DynamicPropertyLookupOnClassesUnsafe{exprType}});
+            return errorRecoveryType(scope);
         }
     }
 
@@ -4026,13 +4021,9 @@ void TypeChecker::checkArgumentList(const ScopePtr& scope, const AstExpr& funNam
                     if (argIndex < argLocations.size())
                         location = argLocations[argIndex];
 
-                    if (FFlag::LuauVariadicOverloadFix)
-                    {
-                        state.location = location;
-                        state.tryUnify(*argIter, vtp->ty);
-                    }
-                    else
-                        unify(*argIter, vtp->ty, scope, location);
+                    state.location = location;
+                    state.tryUnify(*argIter, vtp->ty);
+
                     ++argIter;
                     ++argIndex;
                 }
diff --git a/Analysis/src/Unifier.cpp b/Analysis/src/Unifier.cpp
index c371e81e..0940ea92 100644
--- a/Analysis/src/Unifier.cpp
+++ b/Analysis/src/Unifier.cpp
@@ -18,7 +18,6 @@
 LUAU_FASTINT(LuauTypeInferTypePackLoopLimit)
 LUAU_FASTFLAG(LuauErrorRecoveryType)
 LUAU_FASTFLAGVARIABLE(LuauInstantiateInSubtyping, false)
-LUAU_FASTFLAGVARIABLE(LuauMaintainScopesInUnifier, false)
 LUAU_FASTFLAGVARIABLE(LuauTransitiveSubtyping, false)
 LUAU_FASTFLAGVARIABLE(LuauOccursIsntAlwaysFailure, false)
 LUAU_FASTFLAG(LuauAlwaysCommitInferencesOfFunctionCalls)
@@ -1514,7 +1513,7 @@ struct WeirdIter
         auto freePack = log.getMutable<FreeTypePack>(packId);
 
         level = freePack->level;
-        if (FFlag::LuauMaintainScopesInUnifier && freePack->scope != nullptr)
+        if (freePack->scope != nullptr)
             scope = freePack->scope;
         log.replace(packId, BoundTypePack(newTail));
         packId = newTail;
@@ -1679,11 +1678,8 @@ void Unifier::tryUnify_(TypePackId subTp, TypePackId superTp, bool isFunctionCal
         auto superIter = WeirdIter(superTp, log);
         auto subIter = WeirdIter(subTp, log);
 
-        if (FFlag::LuauMaintainScopesInUnifier)
-        {
-            superIter.scope = scope.get();
-            subIter.scope = scope.get();
-        }
+        superIter.scope = scope.get();
+        subIter.scope = scope.get();
 
         auto mkFreshType = [this](Scope* scope, TypeLevel level) {
             if (FFlag::DebugLuauDeferredConstraintResolution)
diff --git a/Ast/include/Luau/Ast.h b/Ast/include/Luau/Ast.h
index a3908a56..ad5592f5 100644
--- a/Ast/include/Luau/Ast.h
+++ b/Ast/include/Luau/Ast.h
@@ -249,6 +249,7 @@ public:
 enum class ConstantNumberParseResult
 {
     Ok,
+    Imprecise,
     Malformed,
     BinOverflow,
     HexOverflow,
diff --git a/Ast/include/Luau/Location.h b/Ast/include/Luau/Location.h
index 041a2c63..3fc8921a 100644
--- a/Ast/include/Luau/Location.h
+++ b/Ast/include/Luau/Location.h
@@ -1,7 +1,6 @@
 // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
 #pragma once
 
-#include <string>
 namespace Luau
 {
 
@@ -9,7 +8,11 @@ struct Position
 {
     unsigned int line, column;
 
-    Position(unsigned int line, unsigned int column);
+    Position(unsigned int line, unsigned int column)
+        : line(line)
+        , column(column)
+    {
+    }
 
     bool operator==(const Position& rhs) const;
     bool operator!=(const Position& rhs) const;
@@ -25,10 +28,29 @@ struct Location
 {
     Position begin, end;
 
-    Location();
-    Location(const Position& begin, const Position& end);
-    Location(const Position& begin, unsigned int length);
-    Location(const Location& begin, const Location& end);
+    Location()
+        : begin(0, 0)
+        , end(0, 0)
+    {
+    }
+
+    Location(const Position& begin, const Position& end)
+        : begin(begin)
+        , end(end)
+    {
+    }
+
+    Location(const Position& begin, unsigned int length)
+        : begin(begin)
+        , end(begin.line, begin.column + length)
+    {
+    }
+
+    Location(const Location& begin, const Location& end)
+        : begin(begin.begin)
+        , end(end.end)
+    {
+    }
 
     bool operator==(const Location& rhs) const;
     bool operator!=(const Location& rhs) const;
diff --git a/Ast/src/Location.cpp b/Ast/src/Location.cpp
index 40f8e23e..c2c66d9f 100644
--- a/Ast/src/Location.cpp
+++ b/Ast/src/Location.cpp
@@ -1,16 +1,9 @@
 // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
 #include "Luau/Location.h"
-#include <string>
 
 namespace Luau
 {
 
-Position::Position(unsigned int line, unsigned int column)
-    : line(line)
-    , column(column)
-{
-}
-
 bool Position::operator==(const Position& rhs) const
 {
     return this->column == rhs.column && this->line == rhs.line;
@@ -61,30 +54,6 @@ void Position::shift(const Position& start, const Position& oldEnd, const Positi
     }
 }
 
-Location::Location()
-    : begin(0, 0)
-    , end(0, 0)
-{
-}
-
-Location::Location(const Position& begin, const Position& end)
-    : begin(begin)
-    , end(end)
-{
-}
-
-Location::Location(const Position& begin, unsigned int length)
-    : begin(begin)
-    , end(begin.line, begin.column + length)
-{
-}
-
-Location::Location(const Location& begin, const Location& end)
-    : begin(begin.begin)
-    , end(end.end)
-{
-}
-
 bool Location::operator==(const Location& rhs) const
 {
     return this->begin == rhs.begin && this->end == rhs.end;
diff --git a/Ast/src/Parser.cpp b/Ast/src/Parser.cpp
index a9747143..3871ea62 100644
--- a/Ast/src/Parser.cpp
+++ b/Ast/src/Parser.cpp
@@ -24,6 +24,8 @@ LUAU_FASTFLAG(LuauCheckedFunctionSyntax)
 LUAU_FASTFLAGVARIABLE(LuauBetterTypeUnionLimits, false)
 LUAU_FASTFLAGVARIABLE(LuauBetterTypeRecLimits, false)
 
+LUAU_FASTFLAGVARIABLE(LuauParseImpreciseNumber, false)
+
 namespace Luau
 {
 
@@ -2187,6 +2189,12 @@ static ConstantNumberParseResult parseInteger(double& result, const char* data,
             return base == 2 ? ConstantNumberParseResult::BinOverflow : ConstantNumberParseResult::HexOverflow;
     }
 
+    if (FFlag::LuauParseImpreciseNumber)
+    {
+        if (value >= (1ull << 53) && static_cast<unsigned long long>(result) != value)
+            return ConstantNumberParseResult::Imprecise;
+    }
+
     return ConstantNumberParseResult::Ok;
 }
 
@@ -2203,8 +2211,32 @@ static ConstantNumberParseResult parseDouble(double& result, const char* data)
     char* end = nullptr;
     double value = strtod(data, &end);
 
-    result = value;
-    return *end == 0 ? ConstantNumberParseResult::Ok : ConstantNumberParseResult::Malformed;
+    if (FFlag::LuauParseImpreciseNumber)
+    {
+        // trailing non-numeric characters
+        if (*end != 0)
+            return ConstantNumberParseResult::Malformed;
+
+        result = value;
+
+        // for linting, we detect integer constants that are parsed imprecisely
+        // since the check is expensive we only perform it when the number is larger than the precise integer range
+        if (value >= double(1ull << 53) && strspn(data, "0123456789") == strlen(data))
+        {
+            char repr[512];
+            snprintf(repr, sizeof(repr), "%.0f", value);
+
+            if (strcmp(repr, data) != 0)
+                return ConstantNumberParseResult::Imprecise;
+        }
+
+        return ConstantNumberParseResult::Ok;
+    }
+    else
+    {
+        result = value;
+        return *end == 0 ? ConstantNumberParseResult::Ok : ConstantNumberParseResult::Malformed;
+    }
 }
 
 // simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor | FUNCTION body | primaryexp
diff --git a/CLI/Compile.cpp b/CLI/Compile.cpp
index 4f6b54b6..bc1d5c60 100644
--- a/CLI/Compile.cpp
+++ b/CLI/Compile.cpp
@@ -120,6 +120,7 @@ struct CompileStats
 {
     size_t lines;
     size_t bytecode;
+    size_t bytecodeInstructionCount;
     size_t codegen;
 
     double readTime;
@@ -136,6 +137,7 @@ struct CompileStats
         fprintf(fp, "{\
 \"lines\": %zu, \
 \"bytecode\": %zu, \
+\"bytecodeInstructionCount\": %zu, \
 \"codegen\": %zu, \
 \"readTime\": %f, \
 \"miscTime\": %f, \
@@ -153,16 +155,22 @@ struct CompileStats
 \"maxBlockInstructions\": %u, \
 \"regAllocErrors\": %d, \
 \"loweringErrors\": %d\
+}, \
+\"blockLinearizationStats\": {\
+\"constPropInstructionCount\": %u, \
+\"timeSeconds\": %f\
 }}",
-            lines, bytecode, codegen, readTime, miscTime, parseTime, compileTime, codegenTime, lowerStats.totalFunctions, lowerStats.skippedFunctions,
-            lowerStats.spillsToSlot, lowerStats.spillsToRestore, lowerStats.maxSpillSlotsUsed, lowerStats.blocksPreOpt, lowerStats.blocksPostOpt,
-            lowerStats.maxBlockInstructions, lowerStats.regAllocErrors, lowerStats.loweringErrors);
+            lines, bytecode, bytecodeInstructionCount, codegen, readTime, miscTime, parseTime, compileTime, codegenTime, lowerStats.totalFunctions,
+            lowerStats.skippedFunctions, lowerStats.spillsToSlot, lowerStats.spillsToRestore, lowerStats.maxSpillSlotsUsed, lowerStats.blocksPreOpt,
+            lowerStats.blocksPostOpt, lowerStats.maxBlockInstructions, lowerStats.regAllocErrors, lowerStats.loweringErrors,
+            lowerStats.blockLinearizationStats.constPropInstructionCount, lowerStats.blockLinearizationStats.timeSeconds);
     }
 
     CompileStats& operator+=(const CompileStats& that)
     {
         this->lines += that.lines;
         this->bytecode += that.bytecode;
+        this->bytecodeInstructionCount += that.bytecodeInstructionCount;
         this->codegen += that.codegen;
         this->readTime += that.readTime;
         this->miscTime += that.miscTime;
@@ -257,6 +265,7 @@ static bool compileFile(const char* name, CompileFormat format, Luau::CodeGen::A
 
         Luau::compileOrThrow(bcb, result, names, copts());
         stats.bytecode += bcb.getBytecode().size();
+        stats.bytecodeInstructionCount = bcb.getTotalInstructionCount();
         stats.compileTime += recordDeltaTime(currts);
 
         switch (format)
@@ -321,6 +330,30 @@ static int assertionHandler(const char* expr, const char* file, int line, const
     return 1;
 }
 
+std::string escapeFilename(const std::string& filename)
+{
+    std::string escaped;
+    escaped.reserve(filename.size());
+
+    for (const char ch : filename)
+    {
+        switch (ch)
+        {
+        case '\\':
+            escaped.push_back('/');
+            break;
+        case '"':
+            escaped.push_back('\\');
+            escaped.push_back(ch);
+            break;
+        default:
+            escaped.push_back(ch);
+        }
+    }
+
+    return escaped;
+}
+
 int main(int argc, char** argv)
 {
     Luau::assertHandler() = assertionHandler;
@@ -330,6 +363,7 @@ int main(int argc, char** argv)
     CompileFormat compileFormat = CompileFormat::Text;
     Luau::CodeGen::AssemblyOptions::Target assemblyTarget = Luau::CodeGen::AssemblyOptions::Host;
     RecordStats recordStats = RecordStats::None;
+    std::string statsFile("stats.json");
 
     for (int i = 1; i < argc; i++)
     {
@@ -394,6 +428,16 @@ int main(int argc, char** argv)
                 return 1;
             }
         }
+        else if (strncmp(argv[i], "--stats-file=", 13) == 0)
+        {
+            statsFile = argv[i] + 13;
+
+            if (statsFile.size() == 0)
+            {
+                fprintf(stderr, "Error: filename missing for '--stats-file'.\n\n");
+                return 1;
+            }
+        }
         else if (strncmp(argv[i], "--fflags=", 9) == 0)
         {
             setLuauFlags(argv[i] + 9);
@@ -463,7 +507,7 @@ int main(int argc, char** argv)
     if (recordStats != RecordStats::None)
     {
 
-        FILE* fp = fopen("stats.json", "w");
+        FILE* fp = fopen(statsFile.c_str(), "w");
 
         if (!fp)
         {
@@ -480,7 +524,8 @@ int main(int argc, char** argv)
             fprintf(fp, "{\n");
             for (size_t i = 0; i < fileCount; ++i)
             {
-                fprintf(fp, "\"%s\": ", files[i].c_str());
+                std::string escaped(escapeFilename(files[i]));
+                fprintf(fp, "\"%s\": ", escaped.c_str());
                 fileStats[i].serializeToJson(fp);
                 fprintf(fp, i == (fileCount - 1) ? "\n" : ",\n");
             }
diff --git a/CodeGen/include/Luau/CodeGen.h b/CodeGen/include/Luau/CodeGen.h
index 409bc22a..dfa3eeb0 100644
--- a/CodeGen/include/Luau/CodeGen.h
+++ b/CodeGen/include/Luau/CodeGen.h
@@ -80,6 +80,27 @@ struct AssemblyOptions
     void* annotatorContext = nullptr;
 };
 
+struct BlockLinearizationStats
+{
+    unsigned int constPropInstructionCount = 0;
+    double timeSeconds = 0.0;
+
+    BlockLinearizationStats& operator+=(const BlockLinearizationStats& that)
+    {
+        this->constPropInstructionCount += that.constPropInstructionCount;
+        this->timeSeconds += that.timeSeconds;
+
+        return *this;
+    }
+
+    BlockLinearizationStats operator+(const BlockLinearizationStats& other) const
+    {
+        BlockLinearizationStats result(*this);
+        result += other;
+        return result;
+    }
+};
+
 struct LoweringStats
 {
     unsigned totalFunctions = 0;
@@ -94,6 +115,8 @@ struct LoweringStats
     int regAllocErrors = 0;
     int loweringErrors = 0;
 
+    BlockLinearizationStats blockLinearizationStats;
+
     LoweringStats operator+(const LoweringStats& other) const
     {
         LoweringStats result(*this);
@@ -113,6 +136,7 @@ struct LoweringStats
         this->maxBlockInstructions = std::max(this->maxBlockInstructions, that.maxBlockInstructions);
         this->regAllocErrors += that.regAllocErrors;
         this->loweringErrors += that.loweringErrors;
+        this->blockLinearizationStats += that.blockLinearizationStats;
         return *this;
     }
 };
diff --git a/CodeGen/include/Luau/IrData.h b/CodeGen/include/Luau/IrData.h
index 19e082b5..9beee0ac 100644
--- a/CodeGen/include/Luau/IrData.h
+++ b/CodeGen/include/Luau/IrData.h
@@ -600,6 +600,10 @@ enum class IrCmd : uint8_t
     BITCOUNTLZ_UINT,
     BITCOUNTRZ_UINT,
 
+    // Swap byte order in A
+    // A: int
+    BYTESWAP_UINT,
+
     // Calls native libm function with 1 or 2 arguments
     // A: builtin function ID
     // B: double
diff --git a/CodeGen/src/CodeGenLower.h b/CodeGen/src/CodeGenLower.h
index 8fcd832f..484d2dab 100644
--- a/CodeGen/src/CodeGenLower.h
+++ b/CodeGen/src/CodeGenLower.h
@@ -50,6 +50,13 @@ inline void gatherFunctions(std::vector<Proto*>& results, Proto* proto, unsigned
         gatherFunctions(results, proto->p[i], flags);
 }
 
+inline unsigned getInstructionCount(const std::vector<IrInst>& instructions, IrCmd cmd)
+{
+    return unsigned(std::count_if(instructions.begin(), instructions.end(), [&cmd](const IrInst& inst) {
+        return inst.cmd == cmd;
+    }));
+}
+
 template<typename AssemblyBuilder, typename IrLowering>
 inline bool lowerImpl(AssemblyBuilder& build, IrLowering& lowering, IrFunction& function, const std::vector<uint32_t>& sortedBlocks, int bytecodeid,
     AssemblyOptions options)
@@ -269,7 +276,25 @@ inline bool lowerFunction(IrBuilder& ir, AssemblyBuilder& build, ModuleHelpers&
         constPropInBlockChains(ir, useValueNumbering);
 
         if (!FFlag::DebugCodegenOptSize)
+        {
+            double startTime = 0.0;
+            unsigned constPropInstructionCount = 0;
+
+            if (stats)
+            {
+                constPropInstructionCount = getInstructionCount(ir.function.instructions, IrCmd::SUBSTITUTE);
+                startTime = lua_clock();
+            }
+
             createLinearBlocks(ir, useValueNumbering);
+
+            if (stats)
+            {
+                stats->blockLinearizationStats.timeSeconds += lua_clock() - startTime;
+                constPropInstructionCount = getInstructionCount(ir.function.instructions, IrCmd::SUBSTITUTE) - constPropInstructionCount;
+                stats->blockLinearizationStats.constPropInstructionCount += constPropInstructionCount;
+            }
+        }
     }
 
     std::vector<uint32_t> sortedBlocks = getSortedBlockOrder(ir.function);
diff --git a/CodeGen/src/CodeGenUtils.cpp b/CodeGen/src/CodeGenUtils.cpp
index 3cdd20b3..9306ae4c 100644
--- a/CodeGen/src/CodeGenUtils.cpp
+++ b/CodeGen/src/CodeGenUtils.cpp
@@ -531,50 +531,6 @@ const Instruction* executeSETTABLEKS(lua_State* L, const Instruction* pc, StkId
     }
 }
 
-const Instruction* executeNEWCLOSURE(lua_State* L, const Instruction* pc, StkId base, TValue* k)
-{
-    [[maybe_unused]] Closure* cl = clvalue(L->ci->func);
-    Instruction insn = *pc++;
-    StkId ra = VM_REG(LUAU_INSN_A(insn));
-
-    Proto* pv = cl->l.p->p[LUAU_INSN_D(insn)];
-    LUAU_ASSERT(unsigned(LUAU_INSN_D(insn)) < unsigned(cl->l.p->sizep));
-
-    VM_PROTECT_PC(); // luaF_newLclosure may fail due to OOM
-
-    // note: we save closure to stack early in case the code below wants to capture it by value
-    Closure* ncl = luaF_newLclosure(L, pv->nups, cl->env, pv);
-    setclvalue(L, ra, ncl);
-
-    for (int ui = 0; ui < pv->nups; ++ui)
-    {
-        Instruction uinsn = *pc++;
-        LUAU_ASSERT(LUAU_INSN_OP(uinsn) == LOP_CAPTURE);
-
-        switch (LUAU_INSN_A(uinsn))
-        {
-        case LCT_VAL:
-            setobj(L, &ncl->l.uprefs[ui], VM_REG(LUAU_INSN_B(uinsn)));
-            break;
-
-        case LCT_REF:
-            setupvalue(L, &ncl->l.uprefs[ui], luaF_findupval(L, VM_REG(LUAU_INSN_B(uinsn))));
-            break;
-
-        case LCT_UPVAL:
-            setobj(L, &ncl->l.uprefs[ui], VM_UV(LUAU_INSN_B(uinsn)));
-            break;
-
-        default:
-            LUAU_ASSERT(!"Unknown upvalue capture type");
-            LUAU_UNREACHABLE(); // improves switch() codegen by eliding opcode bounds checks
-        }
-    }
-
-    VM_PROTECT(luaC_checkGC(L));
-    return pc;
-}
-
 const Instruction* executeNAMECALL(lua_State* L, const Instruction* pc, StkId base, TValue* k)
 {
     [[maybe_unused]] Closure* cl = clvalue(L->ci->func);
@@ -587,43 +543,19 @@ const Instruction* executeNAMECALL(lua_State* L, const Instruction* pc, StkId ba
 
     if (ttistable(rb))
     {
-        Table* h = hvalue(rb);
-        // note: we can't use nodemask8 here because we need to query the main position of the table, and 8-bit nodemask8 only works
-        // for predictive lookups
-        LuaNode* n = &h->node[tsvalue(kv)->hash & (sizenode(h) - 1)];
+        // note: lvmexecute.cpp version of NAMECALL has two fast paths, but both fast paths are inlined into IR
+        // as such, if we get here we can just use the generic path which makes the fallback path a little faster
 
-        const TValue* mt = 0;
-        const LuaNode* mtn = 0;
-
-        // fast-path: key is in the table in expected slot
-        if (ttisstring(gkey(n)) && tsvalue(gkey(n)) == tsvalue(kv) && !ttisnil(gval(n)))
-        {
-            // note: order of copies allows rb to alias ra+1 or ra
-            setobj2s(L, ra + 1, rb);
-            setobj2s(L, ra, gval(n));
-        }
-        // fast-path: key is absent from the base, table has an __index table, and it has the result in the expected slot
-        else if (gnext(n) == 0 && (mt = fasttm(L, hvalue(rb)->metatable, TM_INDEX)) && ttistable(mt) &&
-                 (mtn = &hvalue(mt)->node[LUAU_INSN_C(insn) & hvalue(mt)->nodemask8]) && ttisstring(gkey(mtn)) && tsvalue(gkey(mtn)) == tsvalue(kv) &&
-                 !ttisnil(gval(mtn)))
-        {
-            // note: order of copies allows rb to alias ra+1 or ra
-            setobj2s(L, ra + 1, rb);
-            setobj2s(L, ra, gval(mtn));
-        }
-        else
-        {
-            // slow-path: handles full table lookup
-            setobj2s(L, ra + 1, rb);
-            L->cachedslot = LUAU_INSN_C(insn);
-            VM_PROTECT(luaV_gettable(L, rb, kv, ra));
-            // save cachedslot to accelerate future lookups; patches currently executing instruction since pc-2 rolls back two pc++
-            VM_PATCH_C(pc - 2, L->cachedslot);
-            // recompute ra since stack might have been reallocated
-            ra = VM_REG(LUAU_INSN_A(insn));
-            if (ttisnil(ra))
-                luaG_methoderror(L, ra + 1, tsvalue(kv));
-        }
+        // slow-path: handles full table lookup
+        setobj2s(L, ra + 1, rb);
+        L->cachedslot = LUAU_INSN_C(insn);
+        VM_PROTECT(luaV_gettable(L, rb, kv, ra));
+        // save cachedslot to accelerate future lookups; patches currently executing instruction since pc-2 rolls back two pc++
+        VM_PATCH_C(pc - 2, L->cachedslot);
+        // recompute ra since stack might have been reallocated
+        ra = VM_REG(LUAU_INSN_A(insn));
+        if (ttisnil(ra))
+            luaG_methoderror(L, ra + 1, tsvalue(kv));
     }
     else
     {
diff --git a/CodeGen/src/CodeGenUtils.h b/CodeGen/src/CodeGenUtils.h
index 7075e348..515a81f0 100644
--- a/CodeGen/src/CodeGenUtils.h
+++ b/CodeGen/src/CodeGenUtils.h
@@ -25,7 +25,6 @@ const Instruction* executeGETGLOBAL(lua_State* L, const Instruction* pc, StkId b
 const Instruction* executeSETGLOBAL(lua_State* L, const Instruction* pc, StkId base, TValue* k);
 const Instruction* executeGETTABLEKS(lua_State* L, const Instruction* pc, StkId base, TValue* k);
 const Instruction* executeSETTABLEKS(lua_State* L, const Instruction* pc, StkId base, TValue* k);
-const Instruction* executeNEWCLOSURE(lua_State* L, const Instruction* pc, StkId base, TValue* k);
 const Instruction* executeNAMECALL(lua_State* L, const Instruction* pc, StkId base, TValue* k);
 const Instruction* executeSETLIST(lua_State* L, const Instruction* pc, StkId base, TValue* k);
 const Instruction* executeFORGPREP(lua_State* L, const Instruction* pc, StkId base, TValue* k);
diff --git a/CodeGen/src/IrDump.cpp b/CodeGen/src/IrDump.cpp
index 483e3e00..fd015b3a 100644
--- a/CodeGen/src/IrDump.cpp
+++ b/CodeGen/src/IrDump.cpp
@@ -309,6 +309,8 @@ const char* getCmdName(IrCmd cmd)
         return "BITCOUNTLZ_UINT";
     case IrCmd::BITCOUNTRZ_UINT:
         return "BITCOUNTRZ_UINT";
+    case IrCmd::BYTESWAP_UINT:
+        return "BYTESWAP_UINT";
     case IrCmd::INVOKE_LIBM:
         return "INVOKE_LIBM";
     case IrCmd::GET_TYPE:
diff --git a/CodeGen/src/IrLoweringA64.cpp b/CodeGen/src/IrLoweringA64.cpp
index 26a3b887..98beb513 100644
--- a/CodeGen/src/IrLoweringA64.cpp
+++ b/CodeGen/src/IrLoweringA64.cpp
@@ -1912,6 +1912,13 @@ void IrLoweringA64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next)
         build.clz(inst.regA64, inst.regA64);
         break;
     }
+    case IrCmd::BYTESWAP_UINT:
+    {
+        inst.regA64 = regs.allocReuse(KindA64::w, index, {inst.a});
+        RegisterA64 temp = tempUint(inst.a);
+        build.rev(inst.regA64, temp);
+        break;
+    }
     case IrCmd::INVOKE_LIBM:
     {
         if (inst.c.kind != IrOpKind::None)
diff --git a/CodeGen/src/IrLoweringX64.cpp b/CodeGen/src/IrLoweringX64.cpp
index b9ff4f1f..df7488a9 100644
--- a/CodeGen/src/IrLoweringX64.cpp
+++ b/CodeGen/src/IrLoweringX64.cpp
@@ -822,7 +822,19 @@ void IrLoweringX64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next)
     case IrCmd::UINT_TO_NUM:
         inst.regX64 = regs.allocReg(SizeX64::xmmword, index);
 
-        build.vcvtsi2sd(inst.regX64, inst.regX64, qwordReg(regOp(inst.a)));
+        // AVX has no uint->double conversion; the source must come from UINT op and they all should clear top 32 bits so we can usually
+        // use 64-bit reg; the one exception is NUM_TO_UINT which doesn't clear top bits
+        if (IrCmd source = function.instOp(inst.a).cmd; source == IrCmd::NUM_TO_UINT)
+        {
+            ScopedRegX64 tmp{regs, SizeX64::dword};
+            build.mov(tmp.reg, regOp(inst.a));
+            build.vcvtsi2sd(inst.regX64, inst.regX64, qwordReg(tmp.reg));
+        }
+        else
+        {
+            LUAU_ASSERT(source != IrCmd::SUBSTITUTE); // we don't process substitutions
+            build.vcvtsi2sd(inst.regX64, inst.regX64, qwordReg(regOp(inst.a)));
+        }
         break;
     case IrCmd::NUM_TO_INT:
         inst.regX64 = regs.allocReg(SizeX64::dword, index);
@@ -1633,6 +1645,16 @@ void IrLoweringX64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next)
         build.setLabel(exit);
         break;
     }
+    case IrCmd::BYTESWAP_UINT:
+    {
+        inst.regX64 = regs.allocRegOrReuse(SizeX64::dword, index, {inst.a});
+
+        if (inst.a.kind != IrOpKind::Inst || inst.regX64 != regOp(inst.a))
+            build.mov(inst.regX64, memRegUintOp(inst.a));
+
+        build.bswap(inst.regX64);
+        break;
+    }
     case IrCmd::INVOKE_LIBM:
     {
         IrCallWrapperX64 callWrap(regs, build, index);
diff --git a/CodeGen/src/IrTranslateBuiltins.cpp b/CodeGen/src/IrTranslateBuiltins.cpp
index 3b6b5def..b7d66ae6 100644
--- a/CodeGen/src/IrTranslateBuiltins.cpp
+++ b/CodeGen/src/IrTranslateBuiltins.cpp
@@ -583,8 +583,8 @@ static BuiltinImplResult translateBuiltinBit32ExtractK(
     return {BuiltinImplType::Full, 1};
 }
 
-static BuiltinImplResult translateBuiltinBit32Countz(
-    IrBuilder& build, LuauBuiltinFunction bfid, int nparams, int ra, int arg, IrOp args, int nresults, int pcpos)
+static BuiltinImplResult translateBuiltinBit32Unary(
+    IrBuilder& build, IrCmd cmd, int nparams, int ra, int arg, IrOp args, int nresults, int pcpos)
 {
     if (nparams < 1 || nresults > 1)
         return {BuiltinImplType::None, -1};
@@ -594,7 +594,6 @@ static BuiltinImplResult translateBuiltinBit32Countz(
 
     IrOp vaui = build.inst(IrCmd::NUM_TO_UINT, va);
 
-    IrCmd cmd = (bfid == LBF_BIT32_COUNTLZ) ? IrCmd::BITCOUNTLZ_UINT : IrCmd::BITCOUNTRZ_UINT;
     IrOp bin = build.inst(cmd, vaui);
 
     IrOp value = build.inst(IrCmd::UINT_TO_NUM, bin);
@@ -816,8 +815,9 @@ BuiltinImplResult translateBuiltin(IrBuilder& build, int bfid, int ra, int arg,
     case LBF_BIT32_EXTRACTK:
         return translateBuiltinBit32ExtractK(build, LuauBuiltinFunction(bfid), nparams, ra, arg, args, nresults, pcpos);
     case LBF_BIT32_COUNTLZ:
+        return translateBuiltinBit32Unary(build, IrCmd::BITCOUNTLZ_UINT, nparams, ra, arg, args, nresults, pcpos);
     case LBF_BIT32_COUNTRZ:
-        return translateBuiltinBit32Countz(build, LuauBuiltinFunction(bfid), nparams, ra, arg, args, nresults, pcpos);
+        return translateBuiltinBit32Unary(build, IrCmd::BITCOUNTRZ_UINT, nparams, ra, arg, args, nresults, pcpos);
     case LBF_BIT32_REPLACE:
         return translateBuiltinBit32Replace(build, LuauBuiltinFunction(bfid), nparams, ra, arg, args, nresults, fallback, pcpos);
     case LBF_TYPE:
@@ -830,6 +830,8 @@ BuiltinImplResult translateBuiltin(IrBuilder& build, int bfid, int ra, int arg,
         return translateBuiltinTableInsert(build, nparams, ra, arg, args, nresults, pcpos);
     case LBF_STRING_LEN:
         return translateBuiltinStringLen(build, nparams, ra, arg, args, nresults, pcpos);
+    case LBF_BIT32_BYTESWAP:
+        return translateBuiltinBit32Unary(build, IrCmd::BYTESWAP_UINT, nparams, ra, arg, args, nresults, pcpos);
     default:
         return {BuiltinImplType::None, -1};
     }
diff --git a/CodeGen/src/IrUtils.cpp b/CodeGen/src/IrUtils.cpp
index ba46dbc9..5e606481 100644
--- a/CodeGen/src/IrUtils.cpp
+++ b/CodeGen/src/IrUtils.cpp
@@ -163,6 +163,7 @@ IrValueKind getCmdValueKind(IrCmd cmd)
     case IrCmd::BITRROTATE_UINT:
     case IrCmd::BITCOUNTLZ_UINT:
     case IrCmd::BITCOUNTRZ_UINT:
+    case IrCmd::BYTESWAP_UINT:
         return IrValueKind::Int;
     case IrCmd::INVOKE_LIBM:
         return IrValueKind::Double;
diff --git a/CodeGen/src/NativeState.cpp b/CodeGen/src/NativeState.cpp
index 7b2f068b..a161987d 100644
--- a/CodeGen/src/NativeState.cpp
+++ b/CodeGen/src/NativeState.cpp
@@ -103,7 +103,6 @@ void initFunctions(NativeState& data)
     data.context.executeGETTABLEKS = executeGETTABLEKS;
     data.context.executeSETTABLEKS = executeSETTABLEKS;
 
-    data.context.executeNEWCLOSURE = executeNEWCLOSURE;
     data.context.executeNAMECALL = executeNAMECALL;
     data.context.executeFORGPREP = executeFORGPREP;
     data.context.executeGETVARARGSMultRet = executeGETVARARGSMultRet;
diff --git a/CodeGen/src/NativeState.h b/CodeGen/src/NativeState.h
index f0b8561c..7670482d 100644
--- a/CodeGen/src/NativeState.h
+++ b/CodeGen/src/NativeState.h
@@ -94,7 +94,6 @@ struct NativeContext
     const Instruction* (*executeSETGLOBAL)(lua_State* L, const Instruction* pc, StkId base, TValue* k) = nullptr;
     const Instruction* (*executeGETTABLEKS)(lua_State* L, const Instruction* pc, StkId base, TValue* k) = nullptr;
     const Instruction* (*executeSETTABLEKS)(lua_State* L, const Instruction* pc, StkId base, TValue* k) = nullptr;
-    const Instruction* (*executeNEWCLOSURE)(lua_State* L, const Instruction* pc, StkId base, TValue* k) = nullptr;
     const Instruction* (*executeNAMECALL)(lua_State* L, const Instruction* pc, StkId base, TValue* k) = nullptr;
     const Instruction* (*executeSETLIST)(lua_State* L, const Instruction* pc, StkId base, TValue* k) = nullptr;
     const Instruction* (*executeFORGPREP)(lua_State* L, const Instruction* pc, StkId base, TValue* k) = nullptr;
diff --git a/CodeGen/src/OptimizeConstProp.cpp b/CodeGen/src/OptimizeConstProp.cpp
index 3315ec96..a37b810d 100644
--- a/CodeGen/src/OptimizeConstProp.cpp
+++ b/CodeGen/src/OptimizeConstProp.cpp
@@ -1168,6 +1168,7 @@ static void constPropInInst(ConstPropState& state, IrBuilder& build, IrFunction&
     case IrCmd::BITLROTATE_UINT:
     case IrCmd::BITCOUNTLZ_UINT:
     case IrCmd::BITCOUNTRZ_UINT:
+    case IrCmd::BYTESWAP_UINT:
     case IrCmd::INVOKE_LIBM:
     case IrCmd::GET_TYPE:
     case IrCmd::GET_TYPEOF:
diff --git a/Compiler/include/Luau/BytecodeBuilder.h b/Compiler/include/Luau/BytecodeBuilder.h
index f5098d17..2d86e412 100644
--- a/Compiler/include/Luau/BytecodeBuilder.h
+++ b/Compiler/include/Luau/BytecodeBuilder.h
@@ -83,6 +83,7 @@ public:
     void pushDebugUpval(StringRef name);
 
     size_t getInstructionCount() const;
+    size_t getTotalInstructionCount() const;
     uint32_t getDebugPC() const;
 
     void addDebugRemark(const char* format, ...) LUAU_PRINTF_ATTR(2, 3);
@@ -232,6 +233,7 @@ private:
     uint32_t currentFunction = ~0u;
     uint32_t mainFunction = ~0u;
 
+    size_t totalInstructionCount = 0;
     std::vector<uint32_t> insns;
     std::vector<int> lines;
     std::vector<Constant> constants;
diff --git a/Compiler/src/BytecodeBuilder.cpp b/Compiler/src/BytecodeBuilder.cpp
index 83fb9ce5..7f545282 100644
--- a/Compiler/src/BytecodeBuilder.cpp
+++ b/Compiler/src/BytecodeBuilder.cpp
@@ -244,6 +244,7 @@ void BytecodeBuilder::endFunction(uint8_t maxstacksize, uint8_t numupvalues, uin
 
     currentFunction = ~0u;
 
+    totalInstructionCount += insns.size();
     insns.clear();
     lines.clear();
     constants.clear();
@@ -539,6 +540,11 @@ size_t BytecodeBuilder::getInstructionCount() const
     return insns.size();
 }
 
+size_t BytecodeBuilder::getTotalInstructionCount() const
+{
+    return totalInstructionCount;
+}
+
 uint32_t BytecodeBuilder::getDebugPC() const
 {
     return uint32_t(insns.size());
diff --git a/Compiler/src/Compiler.cpp b/Compiler/src/Compiler.cpp
index e0a0cac8..c685ffbd 100644
--- a/Compiler/src/Compiler.cpp
+++ b/Compiler/src/Compiler.cpp
@@ -27,7 +27,6 @@ LUAU_FASTINTVARIABLE(LuauCompileInlineThresholdMaxBoost, 300)
 LUAU_FASTINTVARIABLE(LuauCompileInlineDepth, 5)
 
 LUAU_FASTFLAG(LuauFloorDivision)
-LUAU_FASTFLAGVARIABLE(LuauCompileFixContinueValidation2, false)
 LUAU_FASTFLAGVARIABLE(LuauCompileIfElseAndOr, false)
 
 namespace Luau
@@ -2519,14 +2518,9 @@ struct Compiler
         // Optimization: body is a "continue" statement with no "else" => we can directly continue in "then" case
         if (!stat->elsebody && continueStatement != nullptr && !areLocalsCaptured(loops.back().localOffsetContinue))
         {
-            if (FFlag::LuauCompileFixContinueValidation2)
-            {
-                // track continue statement for repeat..until validation (validateContinueUntil)
-                if (!loops.back().continueUsed)
-                    loops.back().continueUsed = continueStatement;
-            }
-            else if (loops.back().untilCondition)
-                validateContinueUntil(continueStatement, loops.back().untilCondition);
+            // track continue statement for repeat..until validation (validateContinueUntil)
+            if (!loops.back().continueUsed)
+                loops.back().continueUsed = continueStatement;
 
             // fallthrough = proceed with the loop body as usual
             std::vector<size_t> elseJump;
@@ -2587,7 +2581,7 @@ struct Compiler
         size_t oldJumps = loopJumps.size();
         size_t oldLocals = localStack.size();
 
-        loops.push_back({oldLocals, oldLocals, nullptr, nullptr});
+        loops.push_back({oldLocals, oldLocals, nullptr});
         hasLoops = true;
 
         size_t loopLabel = bytecode.emitLabel();
@@ -2623,7 +2617,7 @@ struct Compiler
         size_t oldJumps = loopJumps.size();
         size_t oldLocals = localStack.size();
 
-        loops.push_back({oldLocals, oldLocals, stat->condition, nullptr});
+        loops.push_back({oldLocals, oldLocals, nullptr});
         hasLoops = true;
 
         size_t loopLabel = bytecode.emitLabel();
@@ -2648,7 +2642,7 @@ struct Compiler
 
             // if continue was called from this statement, then any local defined after this in the loop body should not be accessed by until condition
             // it is sufficient to check this condition once, as if this holds for the first continue, it must hold for all subsequent continues.
-            if (FFlag::LuauCompileFixContinueValidation2 && loops.back().continueUsed && !continueValidated)
+            if (loops.back().continueUsed && !continueValidated)
             {
                 validateContinueUntil(loops.back().continueUsed, stat->condition, body, i + 1);
                 continueValidated = true;
@@ -2870,7 +2864,7 @@ struct Compiler
         size_t oldLocals = localStack.size();
         size_t oldJumps = loopJumps.size();
 
-        loops.push_back({oldLocals, oldLocals, nullptr, nullptr});
+        loops.push_back({oldLocals, oldLocals, nullptr});
 
         for (int iv = 0; iv < tripCount; ++iv)
         {
@@ -2921,7 +2915,7 @@ struct Compiler
         size_t oldLocals = localStack.size();
         size_t oldJumps = loopJumps.size();
 
-        loops.push_back({oldLocals, oldLocals, nullptr, nullptr});
+        loops.push_back({oldLocals, oldLocals, nullptr});
         hasLoops = true;
 
         // register layout: limit, step, index
@@ -2986,7 +2980,7 @@ struct Compiler
         size_t oldLocals = localStack.size();
         size_t oldJumps = loopJumps.size();
 
-        loops.push_back({oldLocals, oldLocals, nullptr, nullptr});
+        loops.push_back({oldLocals, oldLocals, nullptr});
         hasLoops = true;
 
         // register layout: generator, state, index, variables...
@@ -3398,14 +3392,9 @@ struct Compiler
         {
             LUAU_ASSERT(!loops.empty());
 
-            if (FFlag::LuauCompileFixContinueValidation2)
-            {
-                // track continue statement for repeat..until validation (validateContinueUntil)
-                if (!loops.back().continueUsed)
-                    loops.back().continueUsed = stat;
-            }
-            else if (loops.back().untilCondition)
-                validateContinueUntil(stat, loops.back().untilCondition);
+            // track continue statement for repeat..until validation (validateContinueUntil)
+            if (!loops.back().continueUsed)
+                loops.back().continueUsed = stat;
 
             // before continuing, we need to close all local variables that were captured in closures since loop start
             // normally they are closed by the enclosing blocks, including the loop block, but we're skipping that here
@@ -3488,21 +3477,8 @@ struct Compiler
         }
     }
 
-    void validateContinueUntil(AstStat* cont, AstExpr* condition)
-    {
-        LUAU_ASSERT(!FFlag::LuauCompileFixContinueValidation2);
-        UndefinedLocalVisitor visitor(this);
-        condition->visit(&visitor);
-
-        if (visitor.undef)
-            CompileError::raise(condition->location,
-                "Local %s used in the repeat..until condition is undefined because continue statement on line %d jumps over it",
-                visitor.undef->name.value, cont->location.begin.line + 1);
-    }
-
     void validateContinueUntil(AstStat* cont, AstExpr* condition, AstStatBlock* body, size_t start)
     {
-        LUAU_ASSERT(FFlag::LuauCompileFixContinueValidation2);
         UndefinedLocalVisitor visitor(this);
 
         for (size_t i = start; i < body->body.size; ++i)
@@ -3748,18 +3724,8 @@ struct Compiler
 
         void check(AstLocal* local)
         {
-            if (FFlag::LuauCompileFixContinueValidation2)
-            {
-                if (!undef && locals.contains(local))
-                    undef = local;
-            }
-            else
-            {
-                Local& l = self->locals[local];
-
-                if (!l.allocated && !undef)
-                    undef = local;
-            }
+            if (!undef && locals.contains(local))
+                undef = local;
         }
 
         bool visit(AstExprLocal* node) override
@@ -3904,9 +3870,6 @@ struct Compiler
         size_t localOffset;
         size_t localOffsetContinue;
 
-        // TODO: Remove with LuauCompileFixContinueValidation2
-        AstExpr* untilCondition;
-
         AstStatContinue* continueUsed;
     };
 
diff --git a/Sources.cmake b/Sources.cmake
index 2604514e..fb883d7d 100644
--- a/Sources.cmake
+++ b/Sources.cmake
@@ -156,7 +156,7 @@ target_sources(Luau.Analysis PRIVATE
     Analysis/include/Luau/Cancellation.h
     Analysis/include/Luau/Clone.h
     Analysis/include/Luau/Constraint.h
-    Analysis/include/Luau/ConstraintGraphBuilder.h
+    Analysis/include/Luau/ConstraintGenerator.h
     Analysis/include/Luau/ConstraintSolver.h
     Analysis/include/Luau/ControlFlow.h
     Analysis/include/Luau/DataFlowGraph.h
@@ -223,7 +223,7 @@ target_sources(Luau.Analysis PRIVATE
     Analysis/src/BuiltinDefinitions.cpp
     Analysis/src/Clone.cpp
     Analysis/src/Constraint.cpp
-    Analysis/src/ConstraintGraphBuilder.cpp
+    Analysis/src/ConstraintGenerator.cpp
     Analysis/src/ConstraintSolver.cpp
     Analysis/src/DataFlowGraph.cpp
     Analysis/src/DcrLogger.cpp
@@ -385,8 +385,8 @@ if(TARGET Luau.UnitTest)
         tests/CodeAllocator.test.cpp
         tests/Compiler.test.cpp
         tests/Config.test.cpp
-        tests/ConstraintGraphBuilderFixture.cpp
-        tests/ConstraintGraphBuilderFixture.h
+        tests/ConstraintGeneratorFixture.cpp
+        tests/ConstraintGeneratorFixture.h
         tests/ConstraintSolver.test.cpp
         tests/CostModel.test.cpp
         tests/DataFlowGraph.test.cpp
diff --git a/VM/src/lbuiltins.cpp b/VM/src/lbuiltins.cpp
index 04852e87..e28bb169 100644
--- a/VM/src/lbuiltins.cpp
+++ b/VM/src/lbuiltins.cpp
@@ -1353,7 +1353,7 @@ static int luauF_readinteger(lua_State* L, StkId res, TValue* arg0, int nresults
             return -1;
 
         T val;
-        memcpy(&val, (char*)bufvalue(arg0)->data + offset, sizeof(T));
+        memcpy(&val, (char*)bufvalue(arg0)->data + unsigned(offset), sizeof(T));
         setnvalue(res, double(val));
         return 1;
     }
@@ -1374,10 +1374,11 @@ static int luauF_writeinteger(lua_State* L, StkId res, TValue* arg0, int nresult
             return -1;
 
         unsigned value;
-        luai_num2unsigned(value, nvalue(args + 1));
+        double incoming = nvalue(args + 1);
+        luai_num2unsigned(value, incoming);
 
         T val = T(value);
-        memcpy((char*)bufvalue(arg0)->data + offset, &val, sizeof(T));
+        memcpy((char*)bufvalue(arg0)->data + unsigned(offset), &val, sizeof(T));
         return 0;
     }
 #endif
@@ -1397,7 +1398,12 @@ static int luauF_readfp(lua_State* L, StkId res, TValue* arg0, int nresults, Stk
             return -1;
 
         T val;
-        memcpy(&val, (char*)bufvalue(arg0)->data + offset, sizeof(T));
+#ifdef _MSC_VER
+        // avoid memcpy path on MSVC because it results in integer stack copy + floating-point ops on stack
+        val = *(T*)((char*)bufvalue(arg0)->data + unsigned(offset));
+#else
+        memcpy(&val, (char*)bufvalue(arg0)->data + unsigned(offset), sizeof(T));
+#endif
         setnvalue(res, double(val));
         return 1;
     }
@@ -1418,7 +1424,12 @@ static int luauF_writefp(lua_State* L, StkId res, TValue* arg0, int nresults, St
             return -1;
 
         T val = T(nvalue(args + 1));
-        memcpy((char*)bufvalue(arg0)->data + offset, &val, sizeof(T));
+#ifdef _MSC_VER
+        // avoid memcpy path on MSVC because it results in integer stack copy + floating-point ops on stack
+        *(T*)((char*)bufvalue(arg0)->data + unsigned(offset)) = val;
+#else
+        memcpy((char*)bufvalue(arg0)->data + unsigned(offset), &val, sizeof(T));
+#endif
         return 0;
     }
 #endif
diff --git a/VM/src/ldo.cpp b/VM/src/ldo.cpp
index 6729f155..d13e98f3 100644
--- a/VM/src/ldo.cpp
+++ b/VM/src/ldo.cpp
@@ -17,8 +17,6 @@
 
 #include <string.h>
 
-LUAU_DYNAMIC_FASTFLAGVARIABLE(LuauHandlerClose, false)
-
 /*
 ** {======================================================
 ** Error-recovery functions
@@ -409,7 +407,7 @@ static void resume_handle(lua_State* L, void* ud)
     L->ci = restoreci(L, old_ci);
 
     // close eventual pending closures; this means it's now safe to restore stack
-    luaF_close(L, DFFlag::LuauHandlerClose ? L->ci->base : L->base);
+    luaF_close(L, L->ci->base);
 
     // finish cont call and restore stack to previous ci top
     luau_poscall(L, L->top - n);
diff --git a/bench/tests/sha256.lua b/bench/tests/sha256.lua
index 0e4227a3..a01e801e 100644
--- a/bench/tests/sha256.lua
+++ b/bench/tests/sha256.lua
@@ -132,7 +132,8 @@ function test()
 	local ts0 = os.clock()
 
 	for i = 1, 100 do
-		sha256(input)
+		local res = sha256(input)
+		assert(res == "45849646c50337988ccc877d23fcc0de50d1df7490fdc3b9333aed0de8ab492a")
 	end
 
 	local ts1 = os.clock()
diff --git a/tests/Compiler.test.cpp b/tests/Compiler.test.cpp
index bc9a12ea..35dfd230 100644
--- a/tests/Compiler.test.cpp
+++ b/tests/Compiler.test.cpp
@@ -1909,8 +1909,6 @@ RETURN R0 0
 
 TEST_CASE("LoopContinueIgnoresImplicitConstant")
 {
-    ScopedFastFlag luauCompileFixContinueValidation{"LuauCompileFixContinueValidation2", true};
-
     // this used to crash the compiler :(
     CHECK_EQ("\n" + compileFunction0(R"(
 local _
@@ -1926,8 +1924,6 @@ RETURN R0 0
 
 TEST_CASE("LoopContinueIgnoresExplicitConstant")
 {
-    ScopedFastFlag luauCompileFixContinueValidation{"LuauCompileFixContinueValidation2", true};
-
     // Constants do not allocate locals and 'continue' validation should skip them if their lifetime already started
     CHECK_EQ("\n" + compileFunction0(R"(
 local c = true
@@ -1943,8 +1939,6 @@ RETURN R0 0
 
 TEST_CASE("LoopContinueRespectsExplicitConstant")
 {
-    ScopedFastFlag luauCompileFixContinueValidation{"LuauCompileFixContinueValidation2", true};
-
     // If local lifetime hasn't started, even if it's a constant that will not receive an allocation, it cannot be jumped over
     try
     {
@@ -1969,8 +1963,6 @@ until c
 
 TEST_CASE("LoopContinueIgnoresImplicitConstantAfterInline")
 {
-    ScopedFastFlag luauCompileFixContinueValidation{"LuauCompileFixContinueValidation2", true};
-
     // Inlining might also replace some locals with constants instead of allocating them
     CHECK_EQ("\n" + compileFunction(R"(
 local function inline(f)
@@ -1994,7 +1986,6 @@ RETURN R0 0
 
 TEST_CASE("LoopContinueCorrectlyHandlesImplicitConstantAfterUnroll")
 {
-    ScopedFastFlag sff{"LuauCompileFixContinueValidation2", true};
     ScopedFastInt sfi("LuauCompileLoopUnrollThreshold", 200);
 
     // access to implicit constant that depends on the unrolled loop constant is still invalid even though we can constant-propagate it
diff --git a/tests/Conformance.test.cpp b/tests/Conformance.test.cpp
index b7f77711..2a2017a6 100644
--- a/tests/Conformance.test.cpp
+++ b/tests/Conformance.test.cpp
@@ -435,8 +435,6 @@ static int cxxthrow(lua_State* L)
 
 TEST_CASE("PCall")
 {
-    ScopedFastFlag sff("LuauHandlerClose", true);
-
     runConformance(
         "pcall.lua",
         [](lua_State* L) {
diff --git a/tests/ConstraintGraphBuilderFixture.cpp b/tests/ConstraintGeneratorFixture.cpp
similarity index 62%
rename from tests/ConstraintGraphBuilderFixture.cpp
rename to tests/ConstraintGeneratorFixture.cpp
index 293c26ff..dc1aea80 100644
--- a/tests/ConstraintGraphBuilderFixture.cpp
+++ b/tests/ConstraintGeneratorFixture.cpp
@@ -1,10 +1,10 @@
 // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
-#include "ConstraintGraphBuilderFixture.h"
+#include "ConstraintGeneratorFixture.h"
 
 namespace Luau
 {
 
-ConstraintGraphBuilderFixture::ConstraintGraphBuilderFixture()
+ConstraintGeneratorFixture::ConstraintGeneratorFixture()
     : Fixture()
     , mainModule(new Module)
     , forceTheFlag{"DebugLuauDeferredConstraintResolution", true}
@@ -15,18 +15,18 @@ ConstraintGraphBuilderFixture::ConstraintGraphBuilderFixture()
     BlockedTypePack::nextIndex = 0;
 }
 
-void ConstraintGraphBuilderFixture::generateConstraints(const std::string& code)
+void ConstraintGeneratorFixture::generateConstraints(const std::string& code)
 {
     AstStatBlock* root = parse(code);
     dfg = std::make_unique<DataFlowGraph>(DataFlowGraphBuilder::build(root, NotNull{&ice}));
-    cgb = std::make_unique<ConstraintGraphBuilder>(mainModule, NotNull{&normalizer}, NotNull(&moduleResolver), builtinTypes, NotNull(&ice),
+    cg = std::make_unique<ConstraintGenerator>(mainModule, NotNull{&normalizer}, NotNull(&moduleResolver), builtinTypes, NotNull(&ice),
         frontend.globals.globalScope, /*prepareModuleScope*/ nullptr, &logger, NotNull{dfg.get()}, std::vector<RequireCycle>());
-    cgb->visitModuleRoot(root);
-    rootScope = cgb->rootScope;
-    constraints = Luau::borrowConstraints(cgb->constraints);
+    cg->visitModuleRoot(root);
+    rootScope = cg->rootScope;
+    constraints = Luau::borrowConstraints(cg->constraints);
 }
 
-void ConstraintGraphBuilderFixture::solve(const std::string& code)
+void ConstraintGeneratorFixture::solve(const std::string& code)
 {
     generateConstraints(code);
     ConstraintSolver cs{NotNull{&normalizer}, NotNull{rootScope}, constraints, "MainModule", NotNull(&moduleResolver), {}, &logger, {}};
diff --git a/tests/ConstraintGraphBuilderFixture.h b/tests/ConstraintGeneratorFixture.h
similarity index 81%
rename from tests/ConstraintGraphBuilderFixture.h
rename to tests/ConstraintGeneratorFixture.h
index 5e7fedab..ff362be1 100644
--- a/tests/ConstraintGraphBuilderFixture.h
+++ b/tests/ConstraintGeneratorFixture.h
@@ -1,7 +1,7 @@
 // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
 #pragma once
 
-#include "Luau/ConstraintGraphBuilder.h"
+#include "Luau/ConstraintGenerator.h"
 #include "Luau/ConstraintSolver.h"
 #include "Luau/DcrLogger.h"
 #include "Luau/TypeArena.h"
@@ -13,7 +13,7 @@
 namespace Luau
 {
 
-struct ConstraintGraphBuilderFixture : Fixture
+struct ConstraintGeneratorFixture : Fixture
 {
     TypeArena arena;
     ModulePtr mainModule;
@@ -22,14 +22,14 @@ struct ConstraintGraphBuilderFixture : Fixture
     Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}};
 
     std::unique_ptr<DataFlowGraph> dfg;
-    std::unique_ptr<ConstraintGraphBuilder> cgb;
+    std::unique_ptr<ConstraintGenerator> cg;
     Scope* rootScope = nullptr;
 
     std::vector<NotNull<Constraint>> constraints;
 
     ScopedFastFlag forceTheFlag;
 
-    ConstraintGraphBuilderFixture();
+    ConstraintGeneratorFixture();
 
     void generateConstraints(const std::string& code);
     void solve(const std::string& code);
diff --git a/tests/ConstraintSolver.test.cpp b/tests/ConstraintSolver.test.cpp
index 32cb3cda..204d4d14 100644
--- a/tests/ConstraintSolver.test.cpp
+++ b/tests/ConstraintSolver.test.cpp
@@ -1,6 +1,6 @@
 // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
 
-#include "ConstraintGraphBuilderFixture.h"
+#include "ConstraintGeneratorFixture.h"
 #include "Fixture.h"
 #include "doctest.h"
 
@@ -17,7 +17,7 @@ static TypeId requireBinding(Scope* scope, const char* name)
 
 TEST_SUITE_BEGIN("ConstraintSolver");
 
-TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "hello")
+TEST_CASE_FIXTURE(ConstraintGeneratorFixture, "hello")
 {
     solve(R"(
         local a = 55
@@ -29,7 +29,7 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "hello")
     CHECK("number" == toString(bType));
 }
 
-TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "generic_function")
+TEST_CASE_FIXTURE(ConstraintGeneratorFixture, "generic_function")
 {
     solve(R"(
         local function id(a)
@@ -42,7 +42,7 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "generic_function")
     CHECK("<a>(a) -> a" == toString(idType));
 }
 
-TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "proper_let_generalization")
+TEST_CASE_FIXTURE(ConstraintGeneratorFixture, "proper_let_generalization")
 {
     solve(R"(
         local function a(c)
diff --git a/tests/Error.test.cpp b/tests/Error.test.cpp
index 0a71794f..a1869e88 100644
--- a/tests/Error.test.cpp
+++ b/tests/Error.test.cpp
@@ -17,7 +17,7 @@ TEST_CASE("TypeError_code_should_return_nonzero_code")
 TEST_CASE_FIXTURE(BuiltinsFixture, "metatable_names_show_instead_of_tables")
 {
     frontend.options.retainFullTypeGraphs = false;
-    ScopedFastFlag sff{"LuauStacklessTypeClone2", true};
+    ScopedFastFlag sff{"LuauStacklessTypeClone3", true};
     CheckResult result = check(R"(
 --!strict
 local Account = {}
diff --git a/tests/IrBuilder.test.cpp b/tests/IrBuilder.test.cpp
index 4388c400..bd69cb13 100644
--- a/tests/IrBuilder.test.cpp
+++ b/tests/IrBuilder.test.cpp
@@ -3106,3 +3106,37 @@ bb_1:
 }
 
 TEST_SUITE_END();
+
+TEST_SUITE_BEGIN("Dump");
+
+TEST_CASE_FIXTURE(IrBuilderFixture, "ToDot")
+{
+    IrOp entry = build.block(IrBlockKind::Internal);
+    IrOp a = build.block(IrBlockKind::Internal);
+    IrOp b = build.block(IrBlockKind::Internal);
+    IrOp exit = build.block(IrBlockKind::Internal);
+
+    build.beginBlock(entry);
+    build.inst(IrCmd::JUMP_EQ_TAG, build.inst(IrCmd::LOAD_TAG, build.vmReg(0)), build.constTag(tnumber), a, b);
+
+    build.beginBlock(a);
+    build.inst(IrCmd::STORE_TVALUE, build.vmReg(2), build.inst(IrCmd::LOAD_TVALUE, build.vmReg(1)));
+    build.inst(IrCmd::JUMP, exit);
+
+    build.beginBlock(b);
+    build.inst(IrCmd::STORE_TVALUE, build.vmReg(3), build.inst(IrCmd::LOAD_TVALUE, build.vmReg(1)));
+    build.inst(IrCmd::JUMP, exit);
+
+    build.beginBlock(exit);
+    build.inst(IrCmd::RETURN, build.vmReg(2), build.constInt(2));
+
+    updateUseCounts(build.function);
+    computeCfgInfo(build.function);
+
+    // note: we don't validate the output of these to avoid test churn when dot formatting changes, but we run these to make sure they don't assert/crash
+    toDot(build.function, /* includeInst= */ true);
+    toDotCfg(build.function);
+    toDotDjGraph(build.function);
+}
+
+TEST_SUITE_END();
diff --git a/tests/Linter.test.cpp b/tests/Linter.test.cpp
index 9907d7a1..f71d92ad 100644
--- a/tests/Linter.test.cpp
+++ b/tests/Linter.test.cpp
@@ -1517,8 +1517,6 @@ end
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "DeprecatedApiFenv")
 {
-    ScopedFastFlag sff("LuauLintDeprecatedFenv", true);
-
     LintResult result = lint(R"(
 local f, g, h = ...
 
@@ -1591,8 +1589,6 @@ table.create(42, {} :: {})
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "TableOperationsIndexer")
 {
-    ScopedFastFlag sff("LuauLintTableIndexer", true);
-
     LintResult result = lint(R"(
 local t1 = {} -- ok: empty
 local t2 = {1, 2} -- ok: array
@@ -1827,8 +1823,71 @@ local _ = 0x10000000000000000
 )");
 
     REQUIRE(2 == result.warnings.size());
-    CHECK_EQ(result.warnings[0].text, "Binary number literal exceeded available precision and has been truncated to 2^64");
-    CHECK_EQ(result.warnings[1].text, "Hexadecimal number literal exceeded available precision and has been truncated to 2^64");
+    CHECK_EQ(result.warnings[0].text, "Binary number literal exceeded available precision and was truncated to 2^64");
+    CHECK_EQ(result.warnings[1].text, "Hexadecimal number literal exceeded available precision and was truncated to 2^64");
+}
+
+TEST_CASE_FIXTURE(Fixture, "IntegerParsingDecimalImprecise")
+{
+    ScopedFastFlag sff("LuauParseImpreciseNumber", true);
+
+    LintResult result = lint(R"(
+local _ = 10000000000000000000000000000000000000000000000000000000000000000
+local _ = 10000000000000001
+local _ = -10000000000000001
+
+-- 10^16 = 2^16 * 5^16, 5^16 only requires 38 bits
+local _ = 10000000000000000
+local _ = -10000000000000000
+
+-- smallest possible number that is parsed imprecisely
+local _ = 9007199254740993
+local _ = -9007199254740993
+
+-- note that numbers before and after parse precisely (number after is even => 1 more mantissa bit)
+local _ = 9007199254740992
+local _ = 9007199254740994
+
+-- large powers of two should work as well (this is 2^63)
+local _ = -9223372036854775808
+)");
+
+    REQUIRE(5 == result.warnings.size());
+    CHECK_EQ(result.warnings[0].text, "Number literal exceeded available precision and was truncated to closest representable number");
+    CHECK_EQ(result.warnings[0].location.begin.line, 1);
+    CHECK_EQ(result.warnings[1].text, "Number literal exceeded available precision and was truncated to closest representable number");
+    CHECK_EQ(result.warnings[1].location.begin.line, 2);
+    CHECK_EQ(result.warnings[2].text, "Number literal exceeded available precision and was truncated to closest representable number");
+    CHECK_EQ(result.warnings[2].location.begin.line, 3);
+    CHECK_EQ(result.warnings[3].text, "Number literal exceeded available precision and was truncated to closest representable number");
+    CHECK_EQ(result.warnings[3].location.begin.line, 10);
+    CHECK_EQ(result.warnings[4].text, "Number literal exceeded available precision and was truncated to closest representable number");
+    CHECK_EQ(result.warnings[4].location.begin.line, 11);
+}
+
+TEST_CASE_FIXTURE(Fixture, "IntegerParsingHexImprecise")
+{
+    ScopedFastFlag sff("LuauParseImpreciseNumber", true);
+
+    LintResult result = lint(R"(
+local _ = 0x1234567812345678
+
+-- smallest possible number that is parsed imprecisely
+local _ = 0x20000000000001
+
+-- note that numbers before and after parse precisely (number after is even => 1 more mantissa bit)
+local _ = 0x20000000000000
+local _ = 0x20000000000002
+
+-- large powers of two should work as well (this is 2^63)
+local _ = -9223372036854775808
+)");
+
+    REQUIRE(2 == result.warnings.size());
+    CHECK_EQ(result.warnings[0].text, "Number literal exceeded available precision and was truncated to closest representable number");
+    CHECK_EQ(result.warnings[0].location.begin.line, 1);
+    CHECK_EQ(result.warnings[1].text, "Number literal exceeded available precision and was truncated to closest representable number");
+    CHECK_EQ(result.warnings[1].location.begin.line, 4);
 }
 
 TEST_CASE_FIXTURE(Fixture, "ComparisonPrecedence")
diff --git a/tests/Module.test.cpp b/tests/Module.test.cpp
index 208db5d8..c966968f 100644
--- a/tests/Module.test.cpp
+++ b/tests/Module.test.cpp
@@ -14,7 +14,7 @@
 using namespace Luau;
 
 LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution);
-LUAU_FASTFLAG(LuauStacklessTypeClone2)
+LUAU_FASTFLAG(LuauStacklessTypeClone3)
 
 TEST_SUITE_BEGIN("ModuleTests");
 
@@ -336,7 +336,7 @@ TEST_CASE_FIXTURE(Fixture, "clone_recursion_limit")
     int limit = 400;
 #endif
 
-    ScopedFastFlag sff{"LuauStacklessTypeClone2", false};
+    ScopedFastFlag sff{"LuauStacklessTypeClone3", false};
     ScopedFastInt luauTypeCloneRecursionLimit{"LuauTypeCloneRecursionLimit", limit};
 
     TypeArena src;
@@ -360,7 +360,7 @@ TEST_CASE_FIXTURE(Fixture, "clone_recursion_limit")
 
 TEST_CASE_FIXTURE(Fixture, "clone_iteration_limit")
 {
-    ScopedFastFlag sff{"LuauStacklessTypeClone2", true};
+    ScopedFastFlag sff{"LuauStacklessTypeClone3", true};
     ScopedFastInt sfi{"LuauTypeCloneIterationLimit", 500};
 
     TypeArena src;
@@ -534,4 +534,36 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "clone_table_bound_to_table_bound_to_table")
     REQUIRE(!tableA->boundTo);
 }
 
+TEST_CASE_FIXTURE(BuiltinsFixture, "clone_a_bound_type_to_a_persistent_type")
+{
+    ScopedFastFlag sff{"LuauStacklessTypeClone3", true};
+
+    TypeArena arena;
+
+    TypeId boundTo = arena.addType(BoundType{builtinTypes->numberType});
+    REQUIRE(builtinTypes->numberType->persistent);
+
+    TypeArena dest;
+    CloneState state{builtinTypes};
+    TypeId res = clone(boundTo, dest, state);
+
+    REQUIRE(res == follow(boundTo));
+}
+
+TEST_CASE_FIXTURE(BuiltinsFixture, "clone_a_bound_typepack_to_a_persistent_typepack")
+{
+    ScopedFastFlag sff{"LuauStacklessTypeClone3", true};
+
+    TypeArena arena;
+
+    TypePackId boundTo = arena.addTypePack(BoundTypePack{builtinTypes->neverTypePack});
+    REQUIRE(builtinTypes->neverTypePack->persistent);
+
+    TypeArena dest;
+    CloneState state{builtinTypes};
+    TypePackId res = clone(boundTo, dest, state);
+
+    REQUIRE(res == follow(boundTo));
+}
+
 TEST_SUITE_END();
diff --git a/tests/Normalize.test.cpp b/tests/Normalize.test.cpp
index ee818022..30ec3316 100644
--- a/tests/Normalize.test.cpp
+++ b/tests/Normalize.test.cpp
@@ -31,6 +31,9 @@ struct IsSubtypeFixture : Fixture
 
     bool isConsistentSubtype(TypeId a, TypeId b)
     {
+        // any test that is testing isConsistentSubtype is testing the old solver exclusively!
+        ScopedFastFlag noDcr{"DebugLuauDeferredConstraintResolution", false};
+
         Location location;
         ModulePtr module = getMainModule();
         REQUIRE(module);
@@ -169,7 +172,10 @@ TEST_CASE_FIXTURE(IsSubtypeFixture, "table_with_union_prop")
     TypeId a = requireType("a");
     TypeId b = requireType("b");
 
-    CHECK(isSubtype(a, b));
+    if (FFlag::DebugLuauDeferredConstraintResolution)
+        CHECK(!isSubtype(a, b)); // table properties are invariant
+    else
+        CHECK(isSubtype(a, b));
     CHECK(!isSubtype(b, a));
 }
 
@@ -187,7 +193,10 @@ TEST_CASE_FIXTURE(IsSubtypeFixture, "table_with_any_prop")
     TypeId a = requireType("a");
     TypeId b = requireType("b");
 
-    CHECK(isSubtype(a, b));
+    if (FFlag::DebugLuauDeferredConstraintResolution)
+        CHECK(!isSubtype(a, b)); // table properties are invariant
+    else
+        CHECK(isSubtype(a, b));
     CHECK(!isSubtype(b, a));
     CHECK(isConsistentSubtype(b, a));
 }
@@ -249,7 +258,10 @@ TEST_CASE_FIXTURE(IsSubtypeFixture, "tables")
     TypeId c = requireType("c");
     TypeId d = requireType("d");
 
-    CHECK(isSubtype(a, b));
+    if (FFlag::DebugLuauDeferredConstraintResolution)
+        CHECK(!isSubtype(a, b)); // table properties are invariant
+    else
+        CHECK(isSubtype(a, b));
     CHECK(!isSubtype(b, a));
     CHECK(isConsistentSubtype(b, a));
 
@@ -259,7 +271,10 @@ TEST_CASE_FIXTURE(IsSubtypeFixture, "tables")
     CHECK(isSubtype(d, a));
     CHECK(!isSubtype(a, d));
 
-    CHECK(isSubtype(d, b));
+    if (FFlag::DebugLuauDeferredConstraintResolution)
+        CHECK(!isSubtype(d, b)); // table properties are invariant
+    else
+        CHECK(isSubtype(d, b));
     CHECK(!isSubtype(b, d));
 }
 
@@ -705,6 +720,19 @@ TEST_CASE_FIXTURE(NormalizeFixture, "specific_functions_cannot_be_negated")
     CHECK(nullptr == toNormalizedType("Not<(boolean) -> boolean>"));
 }
 
+TEST_CASE_FIXTURE(NormalizeFixture, "trivial_intersection_inhabited")
+{
+    // this test was used to fix a bug in normalization when working with intersections/unions of the same type.
+
+    TypeId a = arena.addType(FunctionType{builtinTypes->emptyTypePack, builtinTypes->anyTypePack, std::nullopt, false});
+    TypeId c = arena.addType(IntersectionType{{a, a}});
+
+    const NormalizedType* n = normalizer.normalize(c);
+    REQUIRE(n);
+
+    CHECK(normalizer.isInhabited(n));
+}
+
 TEST_CASE_FIXTURE(NormalizeFixture, "bare_negated_boolean")
 {
     // TODO: We don't yet have a way to say number | string | thread | nil | Class | Table | Function
@@ -906,4 +934,12 @@ TEST_CASE_FIXTURE(NormalizeFixture, "normalize_is_exactly_number")
     CHECK(!unionIntersection->isExactlyNumber());
 }
 
+TEST_CASE_FIXTURE(NormalizeFixture, "normalize_unknown")
+{
+    auto nt = toNormalizedType("Not<string> | Not<number>");
+    CHECK(nt);
+    CHECK(nt->isUnknown());
+    CHECK(toString(normalizer.typeFromNormal(*nt)) == "unknown");
+}
+
 TEST_SUITE_END();
diff --git a/tests/Subtyping.test.cpp b/tests/Subtyping.test.cpp
index 9dc193d8..57455244 100644
--- a/tests/Subtyping.test.cpp
+++ b/tests/Subtyping.test.cpp
@@ -857,6 +857,15 @@ TEST_CASE_FIXTURE(SubtypeFixture, "Child & ~GrandchildOne <!: number")
     CHECK_IS_NOT_SUBTYPE(meet(childClass, negate(grandchildOneClass)), builtinTypes->numberType);
 }
 
+TEST_CASE_FIXTURE(SubtypeFixture, "semantic_subtyping_disj")
+{
+    TypeId subTy = builtinTypes->unknownType;
+    TypeId superTy = join(negate(builtinTypes->numberType), negate(builtinTypes->stringType));
+    SubtypingResult result = isSubtype(subTy, superTy);
+    CHECK(result.isSubtype);
+}
+
+
 TEST_CASE_FIXTURE(SubtypeFixture, "t1 where t1 = {trim: (t1) -> string} <: t2 where t2 = {trim: (t2) -> string}")
 {
     TypeId t1 = cyclicTable([&](TypeId ty, TableType* tt) {
diff --git a/tests/TypeInfer.aliases.test.cpp b/tests/TypeInfer.aliases.test.cpp
index 3f6d90fa..d11e8988 100644
--- a/tests/TypeInfer.aliases.test.cpp
+++ b/tests/TypeInfer.aliases.test.cpp
@@ -185,7 +185,6 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_aliases")
     LUAU_REQUIRE_NO_ERRORS(result);
 }
 
-#if 0
 TEST_CASE_FIXTURE(Fixture, "generic_aliases")
 {
     ScopedFastFlag sff[] = {
@@ -200,7 +199,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_aliases")
 
     LUAU_REQUIRE_ERROR_COUNT(1, result);
     const std::string expected =
-        R"(Type 'bad' could not be converted into 'T<number>'; type bad["v"] (string) is not a subtype of T<number>["v"] (number))";
+        R"(Type 'bad' could not be converted into 'T<number>'; at ["v"], string is not a subtype of number)";
     CHECK(result.errors[0].location == Location{{4, 31}, {4, 44}});
     CHECK_EQ(expected, toString(result.errors[0]));
 }
@@ -220,12 +219,11 @@ TEST_CASE_FIXTURE(Fixture, "dependent_generic_aliases")
 
     LUAU_REQUIRE_ERROR_COUNT(1, result);
     const std::string expected =
-        R"(Type 'bad' could not be converted into 'U<number>'; type bad["t"]["v"] (string) is not a subtype of U<number>["t"]["v"] (number))";
+        R"(Type 'bad' could not be converted into 'U<number>'; at ["t"]["v"], string is not a subtype of number)";
 
     CHECK(result.errors[0].location == Location{{4, 31}, {4, 52}});
     CHECK_EQ(expected, toString(result.errors[0]));
 }
-#endif
 
 TEST_CASE_FIXTURE(Fixture, "mutually_recursive_generic_aliases")
 {
diff --git a/tests/TypeInfer.cfa.test.cpp b/tests/TypeInfer.cfa.test.cpp
index 19700d2c..07652c15 100644
--- a/tests/TypeInfer.cfa.test.cpp
+++ b/tests/TypeInfer.cfa.test.cpp
@@ -934,7 +934,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "prototyping_and_visiting_alias_has_the_same_
 {
     ScopedFastFlag sff{"LuauTinyControlFlowAnalysis", true};
 
-    // In CGB, we walk the block to prototype aliases. We then visit the block in-order, which will resolve the prototype to a real type.
+    // In CG, we walk the block to prototype aliases. We then visit the block in-order, which will resolve the prototype to a real type.
     // That second walk assumes that the name occurs in the same `Scope` that the prototype walk had. If we arbitrarily change scope midway
     // through, we'd invoke UB.
     CheckResult result = check(R"(
diff --git a/tests/TypeInfer.classes.test.cpp b/tests/TypeInfer.classes.test.cpp
index 94eec961..a6d3fa5c 100644
--- a/tests/TypeInfer.classes.test.cpp
+++ b/tests/TypeInfer.classes.test.cpp
@@ -426,8 +426,6 @@ TEST_CASE_FIXTURE(ClassFixture, "unions_of_intersections_of_classes")
 
 TEST_CASE_FIXTURE(ClassFixture, "index_instance_property")
 {
-    ScopedFastFlag luauAllowIndexClassParameters{"LuauAllowIndexClassParameters", true};
-
     CheckResult result = check(R"(
         local function execute(object: BaseClass, name: string)
             print(object[name])
@@ -440,8 +438,6 @@ TEST_CASE_FIXTURE(ClassFixture, "index_instance_property")
 
 TEST_CASE_FIXTURE(ClassFixture, "index_instance_property_nonstrict")
 {
-    ScopedFastFlag luauAllowIndexClassParameters{"LuauAllowIndexClassParameters", true};
-
     CheckResult result = check(R"(
         --!nonstrict
 
diff --git a/tests/TypeInfer.intersectionTypes.test.cpp b/tests/TypeInfer.intersectionTypes.test.cpp
index 18b8ab8a..6892c78f 100644
--- a/tests/TypeInfer.intersectionTypes.test.cpp
+++ b/tests/TypeInfer.intersectionTypes.test.cpp
@@ -976,7 +976,6 @@ local y = x["Bar"]
     LUAU_REQUIRE_NO_ERRORS(result);
 }
 
-#if 0
 TEST_CASE_FIXTURE(Fixture, "cli_80596_simplify_degenerate_intersections")
 {
     ScopedFastFlag dcr{"DebugLuauDeferredConstraintResolution", true};
@@ -1026,6 +1025,5 @@ TEST_CASE_FIXTURE(Fixture, "cli_80596_simplify_more_realistic_intersections")
 
     LUAU_REQUIRE_ERRORS(result);
 }
-#endif
 
 TEST_SUITE_END();
diff --git a/tests/TypeInfer.oop.test.cpp b/tests/TypeInfer.oop.test.cpp
index a332dee2..7fe4a2c3 100644
--- a/tests/TypeInfer.oop.test.cpp
+++ b/tests/TypeInfer.oop.test.cpp
@@ -415,7 +415,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "promise_type_error_too_complex" * doctest::t
     // TODO: LTI changes to function call resolution have rendered this test impossibly slow
     // shared self should fix it, but there may be other mitigations possible as well
     REQUIRE(!FFlag::DebugLuauDeferredConstraintResolution);
-    ScopedFastFlag sff{"LuauStacklessTypeClone2", true};
+    ScopedFastFlag sff{"LuauStacklessTypeClone3", true};
 
     frontend.options.retainFullTypeGraphs = false;
 
diff --git a/tests/TypeInfer.singletons.test.cpp b/tests/TypeInfer.singletons.test.cpp
index 97ee15e1..23314535 100644
--- a/tests/TypeInfer.singletons.test.cpp
+++ b/tests/TypeInfer.singletons.test.cpp
@@ -350,7 +350,6 @@ Table type 'a' not compatible with type 'Bad' because the former is missing fiel
     CHECK_EQ(expected, toString(result.errors[0]));
 }
 
-#if 0
 TEST_CASE_FIXTURE(Fixture, "parametric_tagged_union_alias")
 {
     ScopedFastFlag sff[] = {
@@ -372,7 +371,6 @@ TEST_CASE_FIXTURE(Fixture, "parametric_tagged_union_alias")
 
     CHECK(toString(result.errors[0]) == expectedError);
 }
-#endif
 
 TEST_CASE_FIXTURE(Fixture, "if_then_else_expression_singleton_options")
 {
diff --git a/tests/TypeInfer.tables.test.cpp b/tests/TypeInfer.tables.test.cpp
index d5ae004c..b0a8b98d 100644
--- a/tests/TypeInfer.tables.test.cpp
+++ b/tests/TypeInfer.tables.test.cpp
@@ -43,7 +43,10 @@ TEST_CASE_FIXTURE(Fixture, "basic")
 
 TEST_CASE_FIXTURE(Fixture, "augment_table")
 {
-    CheckResult result = check("local t = {}  t.foo = 'bar'");
+    CheckResult result = check(R"(
+        local t = {}
+        t.foo = 'bar'
+    )");
     LUAU_REQUIRE_NO_ERRORS(result);
 
     const TableType* tType = get<TableType>(requireType("t"));
@@ -70,6 +73,35 @@ TEST_CASE_FIXTURE(Fixture, "augment_nested_table")
     CHECK("{ p: { foo: string } }" == toString(requireType("t"), {true}));
 }
 
+TEST_CASE_FIXTURE(Fixture, "assign_key_at_index_expr")
+{
+    CheckResult result = check(R"(
+        function f(t: {[string]: number})
+            t["hello"] = 1
+        end
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+
+    // We had a bug where we forgot to record the astType of this particular node.
+    CHECK("string" == toString(requireTypeAtPosition({2, 19})));
+}
+
+TEST_CASE_FIXTURE(Fixture, "index_expression_is_checked_against_the_indexer_type")
+{
+    CheckResult result = check(R"(
+        function f(t: {[boolean]: number})
+            t["hello"] = 15
+        end
+    )");
+
+    LUAU_REQUIRE_ERROR_COUNT(1, result);
+    if (FFlag::DebugLuauDeferredConstraintResolution)
+        CHECK_MESSAGE(get<CannotExtendTable>(result.errors[0]), "Expected CannotExtendTable but got " << toString(result.errors[0]));
+    else
+        CHECK(get<TypeMismatch>(result.errors[0]));
+}
+
 TEST_CASE_FIXTURE(Fixture, "cannot_augment_sealed_table")
 {
     CheckResult result = check(R"(
diff --git a/tests/TypeInfer.test.cpp b/tests/TypeInfer.test.cpp
index a2a28ae5..a1d5e95a 100644
--- a/tests/TypeInfer.test.cpp
+++ b/tests/TypeInfer.test.cpp
@@ -1453,8 +1453,6 @@ TEST_CASE_FIXTURE(Fixture, "promote_tail_type_packs")
  */
 TEST_CASE_FIXTURE(BuiltinsFixture, "be_sure_to_use_active_txnlog_when_evaluating_a_variadic_overload")
 {
-    ScopedFastFlag sff{"LuauVariadicOverloadFix", true};
-
     CheckResult result = check(R"(
         local function concat<T>(target: {T}, ...: {T} | T): {T}
             return (nil :: any) :: {T}
diff --git a/tests/TypeInfer.tryUnify.test.cpp b/tests/TypeInfer.tryUnify.test.cpp
index cc925cab..9f523ce3 100644
--- a/tests/TypeInfer.tryUnify.test.cpp
+++ b/tests/TypeInfer.tryUnify.test.cpp
@@ -15,6 +15,9 @@ LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution)
 
 struct TryUnifyFixture : Fixture
 {
+    // Cannot use `TryUnifyFixture` under DCR.
+    ScopedFastFlag noDcr{"DebugLuauDeferredConstraintResolution", false};
+
     TypeArena arena;
     ScopePtr globalScope{new Scope{arena.addTypePack({TypeId{}})}};
     InternalErrorReporter iceHandler;
@@ -139,7 +142,7 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "incompatible_tables_are_preserved")
     CHECK_NE(*getMutable<TableType>(&tableOne)->props["foo"].type(), *getMutable<TableType>(&tableTwo)->props["foo"].type());
 }
 
-TEST_CASE_FIXTURE(TryUnifyFixture, "uninhabited_intersection_sub_never")
+TEST_CASE_FIXTURE(Fixture, "uninhabited_intersection_sub_never")
 {
     CheckResult result = check(R"(
         function f(arg : string & number) : never
@@ -149,7 +152,7 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "uninhabited_intersection_sub_never")
     LUAU_REQUIRE_NO_ERRORS(result);
 }
 
-TEST_CASE_FIXTURE(TryUnifyFixture, "uninhabited_intersection_sub_anything")
+TEST_CASE_FIXTURE(Fixture, "uninhabited_intersection_sub_anything")
 {
     CheckResult result = check(R"(
         function f(arg : string & number) : boolean
@@ -159,7 +162,7 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "uninhabited_intersection_sub_anything")
     LUAU_REQUIRE_NO_ERRORS(result);
 }
 
-TEST_CASE_FIXTURE(TryUnifyFixture, "uninhabited_table_sub_never")
+TEST_CASE_FIXTURE(Fixture, "uninhabited_table_sub_never")
 {
     CheckResult result = check(R"(
         function f(arg : { prop : string & number }) : never
@@ -169,7 +172,7 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "uninhabited_table_sub_never")
     LUAU_REQUIRE_NO_ERRORS(result);
 }
 
-TEST_CASE_FIXTURE(TryUnifyFixture, "uninhabited_table_sub_anything")
+TEST_CASE_FIXTURE(Fixture, "uninhabited_table_sub_anything")
 {
     CheckResult result = check(R"(
         function f(arg : { prop : string & number }) : boolean
@@ -179,9 +182,11 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "uninhabited_table_sub_anything")
     LUAU_REQUIRE_NO_ERRORS(result);
 }
 
-TEST_CASE_FIXTURE(TryUnifyFixture, "members_of_failed_typepack_unification_are_unified_with_errorType")
+TEST_CASE_FIXTURE(Fixture, "members_of_failed_typepack_unification_are_unified_with_errorType")
 {
-    ScopedFastFlag sff{"LuauAlwaysCommitInferencesOfFunctionCalls", true};
+    ScopedFastFlag sff[] = {
+        {"LuauAlwaysCommitInferencesOfFunctionCalls", true},
+    };
 
     CheckResult result = check(R"(
         function f(arg: number) end
@@ -196,9 +201,11 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "members_of_failed_typepack_unification_are_u
     CHECK_EQ("*error-type*", toString(requireType("b")));
 }
 
-TEST_CASE_FIXTURE(TryUnifyFixture, "result_of_failed_typepack_unification_is_constrained")
+TEST_CASE_FIXTURE(Fixture, "result_of_failed_typepack_unification_is_constrained")
 {
-    ScopedFastFlag sff{"LuauAlwaysCommitInferencesOfFunctionCalls", true};
+    ScopedFastFlag sff[] = {
+        {"LuauAlwaysCommitInferencesOfFunctionCalls", true},
+    };
 
     CheckResult result = check(R"(
         function f(arg: number) return arg end
@@ -214,7 +221,7 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "result_of_failed_typepack_unification_is_con
     CHECK_EQ("number", toString(requireType("c")));
 }
 
-TEST_CASE_FIXTURE(TryUnifyFixture, "typepack_unification_should_trim_free_tails")
+TEST_CASE_FIXTURE(Fixture, "typepack_unification_should_trim_free_tails")
 {
     CheckResult result = check(R"(
         --!strict
@@ -254,7 +261,7 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "variadic_tails_respect_progress")
     CHECK(state.errors.empty());
 }
 
-TEST_CASE_FIXTURE(TryUnifyFixture, "variadics_should_use_reversed_properly")
+TEST_CASE_FIXTURE(Fixture, "variadics_should_use_reversed_properly")
 {
     CheckResult result = check(R"(
         --!strict
@@ -373,22 +380,12 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "metatables_unify_against_shape_of_free_table
     state.log.commit();
 
     REQUIRE_EQ(state.errors.size(), 1);
-    // clang-format off
-    const std::string expected =
-        (FFlag::DebugLuauDeferredConstraintResolution) ?
-R"(Type
-    '{ @metatable { __index: { foo: string } }, {|  |} }'
-could not be converted into
-    '{- foo: number -}'
-caused by:
-  Type 'number' could not be converted into 'string')" :
-R"(Type
+    const std::string expected = R"(Type
     '{ @metatable {| __index: {| foo: string |} |}, {  } }'
 could not be converted into
     '{- foo: number -}'
 caused by:
   Type 'number' could not be converted into 'string')";
-    // clang-format on
     CHECK_EQ(expected, toString(state.errors[0]));
 }
 
diff --git a/tests/TypePath.test.cpp b/tests/TypePath.test.cpp
index 53127c3d..5d4a49bf 100644
--- a/tests/TypePath.test.cpp
+++ b/tests/TypePath.test.cpp
@@ -93,7 +93,6 @@ TEST_SUITE_BEGIN("TypePathTraversal");
         LUAU_REQUIRE_NO_ERRORS(result); \
     } while (false);
 
-#if 0
 TEST_CASE_FIXTURE(Fixture, "empty_traversal")
 {
     CHECK(traverseForType(builtinTypes->numberType, kEmpty, builtinTypes) == builtinTypes->numberType);
@@ -475,7 +474,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "complex_chains")
         CHECK(*result == builtinTypes->falseType);
     }
 }
-#endif
 
 TEST_SUITE_END(); // TypePathTraversal
 
diff --git a/tests/conformance/bitwise.lua b/tests/conformance/bitwise.lua
index 281ad274..f394dc5b 100644
--- a/tests/conformance/bitwise.lua
+++ b/tests/conformance/bitwise.lua
@@ -140,6 +140,11 @@ assert(bit32.byteswap(0x10203040) == 0x40302010)
 assert(bit32.byteswap(0) == 0)
 assert(bit32.byteswap(-1) == 0xffffffff)
 
+-- bit32.bor(n, 0) must clear top bits
+-- we check this obscuring the constant through a global to make sure this gets evaluated fully
+high32 = 0x42_1234_5678
+assert(bit32.bor(high32, 0) == 0x1234_5678)
+
 --[[
 This test verifies a fix in luauF_replace() where if the 4th
 parameter was not a number, but the first three are numbers, it will
diff --git a/tests/conformance/math.lua b/tests/conformance/math.lua
index d285df78..9262f4ea 100644
--- a/tests/conformance/math.lua
+++ b/tests/conformance/math.lua
@@ -61,6 +61,7 @@ assert(1111111111111111-1111111111111110== 1000.00e-03)
 --     1234567890123456
 assert(1.1 == '1.'+'.1')
 assert('1111111111111111'-'1111111111111110' == tonumber"  +0.001e+3 \n\t")
+assert(10000000000000001 == 10000000000000000)
 
 function eq (a,b,limit)
   if not limit then limit = 10E-10 end
diff --git a/tests/conformance/utf8.lua b/tests/conformance/utf8.lua
index bfd7a1ac..3314216f 100644
--- a/tests/conformance/utf8.lua
+++ b/tests/conformance/utf8.lua
@@ -15,20 +15,33 @@ end
 
 local justone = "^" .. utf8.charpattern .. "$"
 
+-- 't' is the list of codepoints of 's'
+local function checksyntax (s, t)
+  -- creates a string "return '\u{t[1]}...\u{t[n]}'"
+  local ts = {"return '"}
+  for i = 1, #t do ts[i + 1] = string.format("\\u{%x}", t[i]) end
+  ts[#t + 2] = "'"
+  ts = table.concat(ts)
+  -- its execution should result in 's'
+  assert(assert(loadstring(ts))() == s)
+end
+
 assert(not utf8.offset("alo", 5))
 assert(not utf8.offset("alo", -4))
 
 -- 'check' makes several tests over the validity of string 's'.
 -- 't' is the list of codepoints of 's'.
-local function check (s, t, nonstrict)
-  local l = utf8.len(s, 1, -1, nonstrict)
+local function check (s, t)
+  local l = utf8.len(s, 1, -1)
   assert(#t == l and len(s) == l)
   assert(utf8.char(table.unpack(t)) == s)   -- 't' and 's' are equivalent
 
   assert(utf8.offset(s, 0) == 1)
 
+  checksyntax(s, t)
+
   -- creates new table with all codepoints of 's'
-  local t1 = {utf8.codepoint(s, 1, -1, nonstrict)}
+  local t1 = {utf8.codepoint(s, 1, -1)}
   assert(#t == #t1)
   for i = 1, #t do assert(t[i] == t1[i]) end   -- 't' is equal to 't1'
 
@@ -38,25 +51,25 @@ local function check (s, t, nonstrict)
     assert(string.find(string.sub(s, pi, pi1 - 1), justone))
     assert(utf8.offset(s, -1, pi1) == pi)
     assert(utf8.offset(s, i - l - 1) == pi)
-    assert(pi1 - pi == #utf8.char(utf8.codepoint(s, pi, pi, nonstrict)))
+    assert(pi1 - pi == #utf8.char(utf8.codepoint(s, pi, pi)))
     for j = pi, pi1 - 1 do
       assert(utf8.offset(s, 0, j) == pi)
     end
     for j = pi + 1, pi1 - 1 do
       assert(not utf8.len(s, j))
     end
-   assert(utf8.len(s, pi, pi, nonstrict) == 1)
-   assert(utf8.len(s, pi, pi1 - 1, nonstrict) == 1)
-   assert(utf8.len(s, pi, -1, nonstrict) == l - i + 1)
-   assert(utf8.len(s, pi1, -1, nonstrict) == l - i)
-   assert(utf8.len(s, 1, pi, nonstrict) == i)
+   assert(utf8.len(s, pi, pi) == 1)
+   assert(utf8.len(s, pi, pi1 - 1) == 1)
+   assert(utf8.len(s, pi, -1) == l - i + 1)
+   assert(utf8.len(s, pi1, -1) == l - i)
+   assert(utf8.len(s, 1, pi) == i)
   end
 
   local i = 0
-  for p, c in utf8.codes(s, nonstrict) do
+  for p, c in utf8.codes(s) do
     i = i + 1
     assert(c == t[i] and p == utf8.offset(s, i))
-    assert(utf8.codepoint(s, p, p, nonstrict) == c)
+    assert(utf8.codepoint(s, p, p) == c)
   end
   assert(i == #t)
 
@@ -80,9 +93,15 @@ do    -- error indication in utf8.len
     assert(not a and b == p)
   end
   check("abc\xE3def", 4)
-  check("汉字\x80", #("汉字") + 1)
   check("\xF4\x9F\xBF", 1)
   check("\xF4\x9F\xBF\xBF", 1)
+  -- spurious continuation bytes
+  check("汉字\x80", #("汉字") + 1)
+  check("\x80hello", 1)
+  check("hel\x80lo", 4)
+  check("汉字\xBF", #("汉字") + 1)
+  check("\xBFhello", 1)
+  check("hel\xBFlo", 4)
 end
 
 -- errors in utf8.codes
@@ -94,7 +113,17 @@ do
       end)
   end
   errorcodes("ab\xff")
-  -- errorcodes("\u{110000}")
+  errorcodes("\244\144\128\128") -- "\u{110000}" in Lua 5.4
+  errorcodes("in\x80valid")
+  errorcodes("\xbfinvalid")
+  errorcodes("αλφ\xBFα")
+
+  -- calling interation function with invalid arguments
+  local f = utf8.codes("")
+  assert(f("", 2) == nil)
+  assert(f("", -1) == nil)
+  assert(f("", math.mininteger) == nil)
+
 end
 
 -- error in initial position for offset
@@ -131,16 +160,16 @@ do
   -- surrogates
   assert(utf8.codepoint("\u{D7FF}") == 0xD800 - 1)
   assert(utf8.codepoint("\u{E000}") == 0xDFFF + 1)
-  assert(utf8.codepoint("\u{D800}", 1, 1, true) == 0xD800)
-  assert(utf8.codepoint("\u{DFFF}", 1, 1, true) == 0xDFFF)
-  -- assert(utf8.codepoint("\u{7FFFFFFF}", 1, 1, true) == 0x7FFFFFFF)
+  assert(utf8.codepoint("\u{D800}", 1, 1) == 0xD800) -- TODO: this is an error in Lua 5.4
+  assert(utf8.codepoint("\u{DFFF}", 1, 1) == 0xDFFF) -- TODO: this is an error in Lua 5.4
+  assert(pcall(utf8.codepoint, "\253\191\191\191\191\191") == false) -- 0x7FFFFFFF in Lua 5.4 when called with lax=true
 end
 
 assert(utf8.char() == "")
 assert(utf8.char(0, 97, 98, 99, 1) == "\0abc\1")
 
 assert(utf8.codepoint(utf8.char(0x10FFFF)) == 0x10FFFF)
--- assert(utf8.codepoint(utf8.char(0x7FFFFFFF), 1, 1, true) == 2147483647)
+assert(pcall(utf8.char, 0x7FFFFFFF) == false) -- valid in Lua 5.4
 
 checkerror("value out of range", utf8.char, 0x7FFFFFFF + 1)
 checkerror("value out of range", utf8.char, -1)
@@ -154,8 +183,8 @@ end
 invalid("\xF4\x9F\xBF\xBF")
 
 -- surrogates
--- invalid("\u{D800}")
--- invalid("\u{DFFF}")
+-- invalid("\u{D800}") TODO: this is an error in Lua 5.4
+-- invalid("\u{DFFF}") TODO: this is an error in Lua 5.4
 
 -- overlong sequences
 invalid("\xC0\x80")          -- zero
@@ -182,7 +211,7 @@ s = "\0 \x7F\z
 s = string.gsub(s, " ", "")
 check(s, {0,0x7F, 0x80,0x7FF, 0x800,0xFFFF, 0x10000,0x10FFFF})
 
-x = "日本語a-4\0éó"
+local x = "日本語a-4\0éó"
 check(x, {26085, 26412, 35486, 97, 45, 52, 0, 233, 243})
 
 
diff --git a/tests/main.cpp b/tests/main.cpp
index 96a6525f..57d4ee7c 100644
--- a/tests/main.cpp
+++ b/tests/main.cpp
@@ -28,6 +28,7 @@
 #endif
 
 #include <optional>
+#include <stdio.h>
 
 // Indicates if verbose output is enabled; can be overridden via --verbose
 // Currently, this enables output from 'print', but other verbose output could be enabled eventually.
@@ -180,6 +181,70 @@ struct BoostLikeReporter : doctest::IReporter
     void test_case_skipped(const doctest::TestCaseData&) override {}
 };
 
+struct TeamCityReporter : doctest::IReporter
+{
+    const doctest::TestCaseData* currentTest = nullptr;
+
+    TeamCityReporter(const doctest::ContextOptions& in) {}
+
+    void report_query(const doctest::QueryData&) override {}
+
+    void test_run_start() override {}
+
+    void test_run_end(const doctest::TestRunStats& /*in*/) override {}
+
+    void test_case_start(const doctest::TestCaseData& in) override
+    {
+        currentTest = &in;
+        printf("##teamcity[testStarted name='%s: %s' captureStandardOutput='true']\n", in.m_test_suite, in.m_name);
+    }
+
+    // called when a test case is reentered because of unfinished subcases
+    void test_case_reenter(const doctest::TestCaseData& /*in*/) override {}
+
+    void test_case_end(const doctest::CurrentTestCaseStats& in) override
+    {
+        printf("##teamcity[testMetadata testName='%s: %s' name='total_asserts' type='number' value='%d']\n", currentTest->m_test_suite, currentTest->m_name, in.numAssertsCurrentTest);
+        printf("##teamcity[testMetadata testName='%s: %s' name='failed_asserts' type='number' value='%d']\n", currentTest->m_test_suite, currentTest->m_name, in.numAssertsFailedCurrentTest);
+        printf("##teamcity[testMetadata testName='%s: %s' name='runtime' type='number' value='%f']\n", currentTest->m_test_suite, currentTest->m_name, in.seconds);
+
+        if (!in.testCaseSuccess)
+            printf("##teamcity[testFailed name='%s: %s']\n", currentTest->m_test_suite, currentTest->m_name);
+
+        printf("##teamcity[testFinished name='%s: %s']\n", currentTest->m_test_suite, currentTest->m_name);
+    }
+
+    void test_case_exception(const doctest::TestCaseException& in) override {
+        printf("##teamcity[testFailed name='%s: %s' message='Unhandled exception' details='%s']\n", currentTest->m_test_suite, currentTest->m_name, in.error_string.c_str());
+    }
+
+    void subcase_start(const doctest::SubcaseSignature& /*in*/) override {}
+    void subcase_end() override {}
+
+    void log_assert(const doctest::AssertData& ad) override {
+        if(!ad.m_failed)
+            return;
+
+        if (ad.m_decomp.size())
+            fprintf(stderr, "%s(%d): ERROR: %s (%s)\n", ad.m_file, ad.m_line, ad.m_expr, ad.m_decomp.c_str());
+        else
+            fprintf(stderr, "%s(%d): ERROR: %s\n", ad.m_file, ad.m_line, ad.m_expr);
+    }
+
+    void log_message(const doctest::MessageData& md) override {
+        const char* severity = (md.m_severity & doctest::assertType::is_warn) ? "WARNING" : "ERROR";
+        bool isError = md.m_severity & (doctest::assertType::is_require | doctest::assertType::is_check);
+        fprintf(isError ? stderr : stdout, "%s(%d): %s: %s\n", md.m_file, md.m_line, severity, md.m_string.c_str());
+    }
+
+    void test_case_skipped(const doctest::TestCaseData& in) override
+    {
+        printf("##teamcity[testIgnored name='%s: %s' captureStandardOutput='false']\n", in.m_test_suite, in.m_name);
+    }
+};
+
+REGISTER_REPORTER("teamcity", 1, TeamCityReporter);
+
 template<typename T>
 using FValueResult = std::pair<std::string, T>;
 
diff --git a/tools/faillist.txt b/tools/faillist.txt
index 46454bbc..ca8112a1 100644
--- a/tools/faillist.txt
+++ b/tools/faillist.txt
@@ -8,8 +8,6 @@ AstQuery::getDocumentationSymbolAtPosition.table_overloaded_function_prop
 AutocompleteTest.anonymous_autofilled_generic_on_argument_type_pack_vararg
 AutocompleteTest.anonymous_autofilled_generic_type_pack_vararg
 AutocompleteTest.autocomplete_interpolated_string_as_singleton
-AutocompleteTest.autocomplete_oop_implicit_self
-AutocompleteTest.autocomplete_response_perf1
 AutocompleteTest.autocomplete_string_singleton_equality
 AutocompleteTest.autocomplete_string_singleton_escape
 AutocompleteTest.autocomplete_string_singletons
@@ -230,6 +228,7 @@ IntersectionTypes.table_intersection_write_sealed
 IntersectionTypes.table_intersection_write_sealed_indirect
 IntersectionTypes.table_write_sealed_indirect
 IntersectionTypes.union_saturate_overloaded_functions
+isSubtype.any_is_unknown_union_error
 Linter.DeprecatedApiFenv
 Linter.FormatStringTyped
 Linter.TableOperationsIndexer
@@ -312,7 +311,7 @@ TableTests.accidentally_checked_prop_in_opposite_branch
 TableTests.any_when_indexing_into_an_unsealed_table_with_no_indexer_in_nonstrict_mode
 TableTests.array_factory_function
 TableTests.call_method
-TableTests.cannot_change_type_of_unsealed_table_prop
+TableTests.call_method_with_explicit_self_argument
 TableTests.casting_tables_with_props_into_table_with_indexer2
 TableTests.casting_tables_with_props_into_table_with_indexer3
 TableTests.casting_tables_with_props_into_table_with_indexer4
@@ -333,9 +332,7 @@ TableTests.cyclic_shifted_tables
 TableTests.disallow_indexing_into_an_unsealed_table_with_no_indexer_in_strict_mode
 TableTests.dont_crash_when_setmetatable_does_not_produce_a_metatabletypevar
 TableTests.dont_extend_unsealed_tables_in_rvalue_position
-TableTests.dont_hang_when_trying_to_look_up_in_cyclic_metatable_index
 TableTests.dont_leak_free_table_props
-TableTests.dont_quantify_table_that_belongs_to_outer_scope
 TableTests.dont_seal_an_unsealed_table_by_passing_it_to_a_function_that_takes_a_sealed_table
 TableTests.dont_suggest_exact_match_keys
 TableTests.error_detailed_indexer_key
@@ -379,7 +376,6 @@ TableTests.ok_to_set_nil_even_on_non_lvalue_base_expr
 TableTests.okay_to_add_property_to_unsealed_tables_by_assignment
 TableTests.okay_to_add_property_to_unsealed_tables_by_function_call
 TableTests.only_ascribe_synthetic_names_at_module_scope
-TableTests.oop_indexer_works
 TableTests.oop_polymorphic
 TableTests.open_table_unification_2
 TableTests.pass_a_union_of_tables_to_a_function_that_requires_a_table
@@ -424,6 +420,8 @@ TableTests.unification_of_unions_in_a_self_referential_type
 TableTests.unifying_tables_shouldnt_uaf1
 TableTests.used_colon_instead_of_dot
 TableTests.used_dot_instead_of_colon
+TableTests.used_dot_instead_of_colon_but_correctly
+TableTests.when_augmenting_an_unsealed_table_with_an_indexer_apply_the_correct_scope_to_the_indexer_type
 TableTests.wrong_assign_does_hit_indexer
 ToDot.function
 ToString.exhaustive_toString_of_cyclic_table
@@ -557,7 +555,6 @@ TypeInferFunctions.function_is_supertype_of_concrete_functions
 TypeInferFunctions.function_statement_sealed_table_assignment_through_indexer
 TypeInferFunctions.generic_packs_are_not_variadic
 TypeInferFunctions.higher_order_function_2
-TypeInferFunctions.higher_order_function_3
 TypeInferFunctions.higher_order_function_4
 TypeInferFunctions.improved_function_arg_mismatch_error_nonstrict
 TypeInferFunctions.improved_function_arg_mismatch_errors
@@ -596,10 +593,6 @@ TypeInferFunctions.too_many_return_values_no_function
 TypeInferFunctions.vararg_function_is_quantified
 TypeInferLoops.cli_68448_iterators_need_not_accept_nil
 TypeInferLoops.dcr_iteration_explore_raycast_minimization
-TypeInferLoops.dcr_iteration_fragmented_keys
-TypeInferLoops.dcr_iteration_minimized_fragmented_keys_1
-TypeInferLoops.dcr_iteration_minimized_fragmented_keys_2
-TypeInferLoops.dcr_iteration_minimized_fragmented_keys_3
 TypeInferLoops.dcr_iteration_on_never_gives_never
 TypeInferLoops.dcr_xpath_candidates
 TypeInferLoops.for_in_loop
@@ -647,7 +640,6 @@ TypeInferOOP.methods_are_topologically_sorted
 TypeInferOOP.object_constructor_can_refer_to_method_of_self
 TypeInferOOP.promise_type_error_too_complex
 TypeInferOOP.react_style_oo
-TypeInferOOP.table_oop
 TypeInferOperators.add_type_family_works
 TypeInferOperators.and_binexps_dont_unify
 TypeInferOperators.cli_38355_recursive_union
@@ -694,7 +686,6 @@ TypePackTests.type_alias_type_packs_import
 TypePackTests.type_packs_with_tails_in_vararg_adjustment
 TypePackTests.unify_variadic_tails_in_arguments
 TypePackTests.unify_variadic_tails_in_arguments_free
-TypePackTests.variadic_argument_tail
 TypeSingletons.enums_using_singletons_mismatch
 TypeSingletons.error_detailed_tagged_union_mismatch_bool
 TypeSingletons.error_detailed_tagged_union_mismatch_string