diff --git a/Analysis/include/Luau/Anyification.h b/Analysis/include/Luau/Anyification.h
index ee8d6689..9dd7d8e0 100644
--- a/Analysis/include/Luau/Anyification.h
+++ b/Analysis/include/Luau/Anyification.h
@@ -19,6 +19,7 @@ using ScopePtr = std::shared_ptr<Scope>;
 // A substitution which replaces free types by any
 struct Anyification : Substitution
 {
+    Anyification(TypeArena* arena, NotNull<Scope> scope, InternalErrorReporter* iceHandler, TypeId anyType, TypePackId anyTypePack);
     Anyification(TypeArena* arena, const ScopePtr& scope, InternalErrorReporter* iceHandler, TypeId anyType, TypePackId anyTypePack);
     NotNull<Scope> scope;
     InternalErrorReporter* iceHandler;
@@ -35,4 +36,4 @@ struct Anyification : Substitution
     bool ignoreChildren(TypePackId ty) override;
 };
 
-}
\ No newline at end of file
+} // namespace Luau
\ No newline at end of file
diff --git a/Analysis/include/Luau/BuiltinDefinitions.h b/Analysis/include/Luau/BuiltinDefinitions.h
index 07d897b2..28a4368e 100644
--- a/Analysis/include/Luau/BuiltinDefinitions.h
+++ b/Analysis/include/Luau/BuiltinDefinitions.h
@@ -34,6 +34,7 @@ TypeId makeFunction( // Polymorphic
     std::initializer_list<TypeId> paramTypes, std::initializer_list<std::string> paramNames, std::initializer_list<TypeId> retTypes);
 
 void attachMagicFunction(TypeId ty, MagicFunction fn);
+void attachDcrMagicFunction(TypeId ty, DcrMagicFunction fn);
 
 Property makeProperty(TypeId ty, std::optional<std::string> documentationSymbol = std::nullopt);
 void assignPropDocumentationSymbols(TableTypeVar::Props& props, const std::string& baseName);
diff --git a/Analysis/include/Luau/Constraint.h b/Analysis/include/Luau/Constraint.h
index e9f04e79..d5cfcf3f 100644
--- a/Analysis/include/Luau/Constraint.h
+++ b/Analysis/include/Luau/Constraint.h
@@ -56,6 +56,10 @@ struct UnaryConstraint
     TypeId resultType;
 };
 
+// let L : leftType
+// let R : rightType
+// in
+//     L op R : resultType
 struct BinaryConstraint
 {
     AstExprBinary::Op op;
@@ -64,6 +68,14 @@ struct BinaryConstraint
     TypeId resultType;
 };
 
+// iteratee is iterable
+// iterators is the iteration types.
+struct IterableConstraint
+{
+    TypePackId iterator;
+    TypePackId variables;
+};
+
 // name(namedType) = name
 struct NameConstraint
 {
@@ -78,20 +90,31 @@ struct TypeAliasExpansionConstraint
     TypeId target;
 };
 
-using ConstraintV = Variant<SubtypeConstraint, PackSubtypeConstraint, GeneralizationConstraint, InstantiationConstraint, UnaryConstraint,
-    BinaryConstraint, NameConstraint, TypeAliasExpansionConstraint>;
 using ConstraintPtr = std::unique_ptr<struct Constraint>;
 
+struct FunctionCallConstraint
+{
+    std::vector<NotNull<const Constraint>> innerConstraints;
+    TypeId fn;
+    TypePackId result;
+    class AstExprCall* astFragment;
+};
+
+using ConstraintV = Variant<SubtypeConstraint, PackSubtypeConstraint, GeneralizationConstraint, InstantiationConstraint, UnaryConstraint,
+    BinaryConstraint, IterableConstraint, NameConstraint, TypeAliasExpansionConstraint, FunctionCallConstraint>;
+
 struct Constraint
 {
-    Constraint(ConstraintV&& c, NotNull<Scope> scope);
+    Constraint(NotNull<Scope> scope, const Location& location, ConstraintV&& c);
 
     Constraint(const Constraint&) = delete;
     Constraint& operator=(const Constraint&) = delete;
 
-    ConstraintV c;
-    std::vector<NotNull<Constraint>> dependencies;
     NotNull<Scope> scope;
+    Location location;
+    ConstraintV c;
+
+    std::vector<NotNull<Constraint>> dependencies;
 };
 
 inline Constraint& asMutable(const Constraint& c)
diff --git a/Analysis/include/Luau/ConstraintGraphBuilder.h b/Analysis/include/Luau/ConstraintGraphBuilder.h
index 0e41e1ee..1cba0d33 100644
--- a/Analysis/include/Luau/ConstraintGraphBuilder.h
+++ b/Analysis/include/Luau/ConstraintGraphBuilder.h
@@ -9,6 +9,7 @@
 #include "Luau/Ast.h"
 #include "Luau/Constraint.h"
 #include "Luau/Module.h"
+#include "Luau/ModuleResolver.h"
 #include "Luau/NotNull.h"
 #include "Luau/Symbol.h"
 #include "Luau/TypeVar.h"
@@ -51,12 +52,15 @@ struct ConstraintGraphBuilder
     // It is pretty uncommon for constraint generation to itself produce errors, but it can happen.
     std::vector<TypeError> errors;
 
+    // Needed to resolve modules to make 'require' import types properly.
+    NotNull<ModuleResolver> moduleResolver;
     // Occasionally constraint generation needs to produce an ICE.
     const NotNull<InternalErrorReporter> ice;
 
     ScopePtr globalScope;
 
-    ConstraintGraphBuilder(const ModuleName& moduleName, ModulePtr module, TypeArena* arena, NotNull<InternalErrorReporter> ice, const ScopePtr& globalScope);
+    ConstraintGraphBuilder(const ModuleName& moduleName, ModulePtr module, TypeArena* arena, NotNull<ModuleResolver> moduleResolver,
+        NotNull<InternalErrorReporter> ice, const ScopePtr& globalScope);
 
     /**
      * Fabricates a new free type belonging to a given scope.
@@ -82,7 +86,7 @@ struct ConstraintGraphBuilder
      * @param scope the scope to add the constraint to.
      * @param cv the constraint variant to add.
      */
-    void addConstraint(const ScopePtr& scope, ConstraintV cv);
+    void addConstraint(const ScopePtr& scope, const Location& location, ConstraintV cv);
 
     /**
      * Adds a constraint to a given scope.
@@ -104,6 +108,7 @@ struct ConstraintGraphBuilder
     void visit(const ScopePtr& scope, AstStatBlock* block);
     void visit(const ScopePtr& scope, AstStatLocal* local);
     void visit(const ScopePtr& scope, AstStatFor* for_);
+    void visit(const ScopePtr& scope, AstStatForIn* forIn);
     void visit(const ScopePtr& scope, AstStatWhile* while_);
     void visit(const ScopePtr& scope, AstStatRepeat* repeat);
     void visit(const ScopePtr& scope, AstStatLocalFunction* function);
@@ -117,8 +122,6 @@ struct ConstraintGraphBuilder
     void visit(const ScopePtr& scope, AstStatDeclareClass* declareClass);
     void visit(const ScopePtr& scope, AstStatDeclareFunction* declareFunction);
 
-    TypePackId checkExprList(const ScopePtr& scope, const AstArray<AstExpr*>& exprs);
-
     TypePackId checkPack(const ScopePtr& scope, AstArray<AstExpr*> exprs);
     TypePackId checkPack(const ScopePtr& scope, AstExpr* expr);
 
diff --git a/Analysis/include/Luau/ConstraintSolver.h b/Analysis/include/Luau/ConstraintSolver.h
index a270ec99..002aa947 100644
--- a/Analysis/include/Luau/ConstraintSolver.h
+++ b/Analysis/include/Luau/ConstraintSolver.h
@@ -17,6 +17,8 @@ namespace Luau
 // never dereference this pointer.
 using BlockedConstraintId = const void*;
 
+struct ModuleResolver;
+
 struct InstantiationSignature
 {
     TypeFun fn;
@@ -42,6 +44,7 @@ struct ConstraintSolver
     // The entire set of constraints that the solver is trying to resolve.
     std::vector<NotNull<Constraint>> constraints;
     NotNull<Scope> rootScope;
+    ModuleName currentModuleName;
 
     // Constraints that the solver has generated, rather than sourcing from the
     // scope tree.
@@ -63,9 +66,13 @@ struct ConstraintSolver
     // Recorded errors that take place within the solver.
     ErrorVec errors;
 
+    NotNull<ModuleResolver> moduleResolver;
+    std::vector<RequireCycle> requireCycles;
+
     ConstraintSolverLogger logger;
 
-    explicit ConstraintSolver(TypeArena* arena, NotNull<Scope> rootScope);
+    explicit ConstraintSolver(TypeArena* arena, NotNull<Scope> rootScope, ModuleName moduleName, NotNull<ModuleResolver> moduleResolver,
+        std::vector<RequireCycle> requireCycles);
 
     /**
      * Attempts to dispatch all pending constraints and reach a type solution
@@ -86,8 +93,17 @@ struct ConstraintSolver
     bool tryDispatch(const InstantiationConstraint& c, NotNull<const Constraint> constraint, bool force);
     bool tryDispatch(const UnaryConstraint& c, NotNull<const Constraint> constraint, bool force);
     bool tryDispatch(const BinaryConstraint& c, NotNull<const Constraint> constraint, bool force);
+    bool tryDispatch(const IterableConstraint& c, NotNull<const Constraint> constraint, bool force);
     bool tryDispatch(const NameConstraint& c, NotNull<const Constraint> constraint);
     bool tryDispatch(const TypeAliasExpansionConstraint& c, NotNull<const Constraint> constraint);
+    bool tryDispatch(const FunctionCallConstraint& c, NotNull<const Constraint> constraint);
+
+    // for a, ... in some_table do
+    bool tryDispatchIterableTable(TypeId iteratorTy, const IterableConstraint& c, NotNull<const Constraint> constraint, bool force);
+
+    // for a, ... in next_function, t, ... do
+    bool tryDispatchIterableFunction(
+        TypeId nextTy, TypeId tableTy, TypeId firstIndexTy, const IterableConstraint& c, NotNull<const Constraint> constraint, bool force);
 
     void block(NotNull<const Constraint> target, NotNull<const Constraint> constraint);
     /**
@@ -108,6 +124,11 @@ struct ConstraintSolver
      */
     bool isBlocked(TypeId ty);
 
+    /**
+     * @returns true if the TypePackId is in a blocked state.
+     */
+    bool isBlocked(TypePackId tp);
+
     /**
      * Returns whether the constraint is blocked on anything.
      * @param constraint the constraint to check.
@@ -133,10 +154,22 @@ struct ConstraintSolver
     /** Pushes a new solver constraint to the solver.
      * @param cv the body of the constraint.
      **/
-    void pushConstraint(ConstraintV cv, NotNull<Scope> scope);
+    void pushConstraint(NotNull<Scope> scope, const Location& location, ConstraintV cv);
+
+    /**
+     * Attempts to resolve a module from its module information. Returns the
+     * module-level return type of the module, or the error type if one cannot
+     * be found. Reports errors to the solver if the module cannot be found or
+     * the require is illegal.
+     * @param module the module information to look up.
+     * @param location the location where the require is taking place; used for
+     * error locations.
+     **/
+    TypeId resolveModule(const ModuleInfo& module, const Location& location);
 
     void reportError(TypeErrorData&& data, const Location& location);
     void reportError(TypeError e);
+
 private:
     /**
      * Marks a constraint as being blocked on a type or type pack. The constraint
@@ -154,6 +187,8 @@ private:
      * @param progressed the type or type pack pointer that has progressed.
      **/
     void unblock_(BlockedConstraintId progressed);
+
+    ToStringOptions opts;
 };
 
 void dump(NotNull<Scope> rootScope, struct ToStringOptions& opts);
diff --git a/Analysis/include/Luau/ConstraintSolverLogger.h b/Analysis/include/Luau/ConstraintSolverLogger.h
index 55170c42..65aa9a7e 100644
--- a/Analysis/include/Luau/ConstraintSolverLogger.h
+++ b/Analysis/include/Luau/ConstraintSolverLogger.h
@@ -16,7 +16,8 @@ struct ConstraintSolverLogger
 {
     std::string compileOutput();
     void captureBoundarySnapshot(const Scope* rootScope, std::vector<NotNull<const Constraint>>& unsolvedConstraints);
-    void prepareStepSnapshot(const Scope* rootScope, NotNull<const Constraint> current, std::vector<NotNull<const Constraint>>& unsolvedConstraints, bool force);
+    void prepareStepSnapshot(
+        const Scope* rootScope, NotNull<const Constraint> current, std::vector<NotNull<const Constraint>>& unsolvedConstraints, bool force);
     void commitPreparedStepSnapshot();
 
 private:
diff --git a/Analysis/include/Luau/Frontend.h b/Analysis/include/Luau/Frontend.h
index f8da3273..55612689 100644
--- a/Analysis/include/Luau/Frontend.h
+++ b/Analysis/include/Luau/Frontend.h
@@ -157,7 +157,7 @@ struct Frontend
     ScopePtr getGlobalScope();
 
 private:
-    ModulePtr check(const SourceModule& sourceModule, Mode mode, const ScopePtr& environmentScope);
+    ModulePtr check(const SourceModule& sourceModule, Mode mode, const ScopePtr& environmentScope, std::vector<RequireCycle> requireCycles);
 
     std::pair<SourceNode*, SourceModule*> getSourceNode(CheckResult& checkResult, const ModuleName& name);
     SourceModule parse(const ModuleName& name, std::string_view src, const ParseOptions& parseOptions);
diff --git a/Analysis/include/Luau/Scope.h b/Analysis/include/Luau/Scope.h
index dc123335..b7569d8e 100644
--- a/Analysis/include/Luau/Scope.h
+++ b/Analysis/include/Luau/Scope.h
@@ -40,6 +40,9 @@ struct Scope
     std::optional<TypePackId> varargPack;
     // All constraints belonging to this scope.
     std::vector<ConstraintPtr> constraints;
+    // Constraints belonging to this scope that are queued manually by other
+    // constraints.
+    std::vector<ConstraintPtr> unqueuedConstraints;
 
     TypeLevel level;
 
diff --git a/Analysis/include/Luau/ToString.h b/Analysis/include/Luau/ToString.h
index eabbc2be..61e07e9f 100644
--- a/Analysis/include/Luau/ToString.h
+++ b/Analysis/include/Luau/ToString.h
@@ -92,7 +92,6 @@ inline std::string toString(const Constraint& c)
     return toString(c, ToStringOptions{});
 }
 
-
 std::string toString(const TypeVar& tv, ToStringOptions& opts);
 std::string toString(const TypePackVar& tp, ToStringOptions& opts);
 
diff --git a/Analysis/include/Luau/TypeArena.h b/Analysis/include/Luau/TypeArena.h
index be36f19c..decc8c59 100644
--- a/Analysis/include/Luau/TypeArena.h
+++ b/Analysis/include/Luau/TypeArena.h
@@ -29,9 +29,10 @@ struct TypeArena
     TypeId addTV(TypeVar&& tv);
 
     TypeId freshType(TypeLevel level);
+    TypeId freshType(Scope* scope);
 
     TypePackId addTypePack(std::initializer_list<TypeId> types);
-    TypePackId addTypePack(std::vector<TypeId> types);
+    TypePackId addTypePack(std::vector<TypeId> types, std::optional<TypePackId> tail = {});
     TypePackId addTypePack(TypePack pack);
     TypePackId addTypePack(TypePackVar pack);
 
diff --git a/Analysis/include/Luau/TypeInfer.h b/Analysis/include/Luau/TypeInfer.h
index e253eddf..0b427946 100644
--- a/Analysis/include/Luau/TypeInfer.h
+++ b/Analysis/include/Luau/TypeInfer.h
@@ -166,7 +166,8 @@ struct TypeChecker
      */
     bool unify(TypeId subTy, TypeId superTy, const ScopePtr& scope, const Location& location);
     bool unify(TypeId subTy, TypeId superTy, const ScopePtr& scope, const Location& location, const UnifierOptions& options);
-    bool unify(TypePackId subTy, TypePackId superTy, const ScopePtr& scope, const Location& location, CountMismatch::Context ctx = CountMismatch::Context::Arg);
+    bool unify(TypePackId subTy, TypePackId superTy, const ScopePtr& scope, const Location& location,
+        CountMismatch::Context ctx = CountMismatch::Context::Arg);
 
     /** Attempt to unify the types.
      * If this fails, and the subTy type can be instantiated, do so and try unification again.
diff --git a/Analysis/include/Luau/TypePack.h b/Analysis/include/Luau/TypePack.h
index b17003b1..8269230b 100644
--- a/Analysis/include/Luau/TypePack.h
+++ b/Analysis/include/Luau/TypePack.h
@@ -15,6 +15,7 @@ struct TypeArena;
 
 struct TypePack;
 struct VariadicTypePack;
+struct BlockedTypePack;
 
 struct TypePackVar;
 
@@ -24,7 +25,7 @@ using TypePackId = const TypePackVar*;
 using FreeTypePack = Unifiable::Free;
 using BoundTypePack = Unifiable::Bound<TypePackId>;
 using GenericTypePack = Unifiable::Generic;
-using TypePackVariant = Unifiable::Variant<TypePackId, TypePack, VariadicTypePack>;
+using TypePackVariant = Unifiable::Variant<TypePackId, TypePack, VariadicTypePack, BlockedTypePack>;
 
 /* A TypePack is a rope-like string of TypeIds.  We use this structure to encode
  * notions like packs of unknown length and packs of any length, as well as more
@@ -43,6 +44,17 @@ struct VariadicTypePack
     bool hidden = false; // if true, we don't display this when toString()ing a pack with this variadic as its tail.
 };
 
+/**
+ * Analogous to a BlockedTypeVar.
+ */
+struct BlockedTypePack
+{
+    BlockedTypePack();
+    size_t index;
+
+    static size_t nextIndex;
+};
+
 struct TypePackVar
 {
     explicit TypePackVar(const TypePackVariant& ty);
diff --git a/Analysis/include/Luau/TypeUtils.h b/Analysis/include/Luau/TypeUtils.h
index 0aff5a7d..6c611fb2 100644
--- a/Analysis/include/Luau/TypeUtils.h
+++ b/Analysis/include/Luau/TypeUtils.h
@@ -11,12 +11,16 @@
 namespace Luau
 {
 
+struct TxnLog;
+
 using ScopePtr = std::shared_ptr<struct Scope>;
 
 std::optional<TypeId> findMetatableEntry(ErrorVec& errors, TypeId type, const std::string& entry, Location location);
 std::optional<TypeId> findTablePropertyRespectingMeta(ErrorVec& errors, TypeId ty, const std::string& name, Location location);
-std::optional<TypeId> getIndexTypeFromType(
-    const ScopePtr& scope, ErrorVec& errors, TypeArena* arena, TypeId type, const std::string& prop, const Location& location, bool addErrors,
-    InternalErrorReporter& handle);
+std::optional<TypeId> getIndexTypeFromType(const ScopePtr& scope, ErrorVec& errors, TypeArena* arena, TypeId type, const std::string& prop,
+    const Location& location, bool addErrors, InternalErrorReporter& handle);
+
+// Returns the minimum and maximum number of types the argument list can accept.
+std::pair<size_t, std::optional<size_t>> getParameterExtents(const TxnLog* log, TypePackId tp);
 
 } // namespace Luau
diff --git a/Analysis/include/Luau/TypeVar.h b/Analysis/include/Luau/TypeVar.h
index 35b37394..e67b3601 100644
--- a/Analysis/include/Luau/TypeVar.h
+++ b/Analysis/include/Luau/TypeVar.h
@@ -1,11 +1,13 @@
 // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
 #pragma once
 
+#include "Luau/Ast.h"
 #include "Luau/DenseHash.h"
 #include "Luau/Predicate.h"
 #include "Luau/Unifiable.h"
 #include "Luau/Variant.h"
 #include "Luau/Common.h"
+#include "Luau/NotNull.h"
 
 #include <set>
 #include <string>
@@ -262,6 +264,8 @@ struct WithPredicate
 using MagicFunction = std::function<std::optional<WithPredicate<TypePackId>>(
     struct TypeChecker&, const std::shared_ptr<struct Scope>&, const class AstExprCall&, WithPredicate<TypePackId>)>;
 
+using DcrMagicFunction = std::function<bool(NotNull<struct ConstraintSolver>, TypePackId, const class AstExprCall*)>;
+
 struct FunctionTypeVar
 {
     // Global monomorphic function
@@ -287,7 +291,8 @@ struct FunctionTypeVar
     std::vector<std::optional<FunctionArgument>> argNames;
     TypePackId retTypes;
     std::optional<FunctionDefinition> definition;
-    MagicFunction magicFunction = nullptr; // Function pointer, can be nullptr.
+    MagicFunction magicFunction = nullptr;       // Function pointer, can be nullptr.
+    DcrMagicFunction dcrMagicFunction = nullptr; // can be nullptr
     bool hasSelf;
     Tags tags;
     bool hasNoGenerics = false;
@@ -462,8 +467,9 @@ struct TypeFun
  */
 struct PendingExpansionTypeVar
 {
-    PendingExpansionTypeVar(TypeFun fn, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments);
-    TypeFun fn;
+    PendingExpansionTypeVar(std::optional<AstName> prefix, AstName name, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments);
+    std::optional<AstName> prefix;
+    AstName name;
     std::vector<TypeId> typeArguments;
     std::vector<TypePackId> packArguments;
     size_t index;
diff --git a/Analysis/include/Luau/Unifier.h b/Analysis/include/Luau/Unifier.h
index 312b0584..c7eb51a6 100644
--- a/Analysis/include/Luau/Unifier.h
+++ b/Analysis/include/Luau/Unifier.h
@@ -59,7 +59,8 @@ struct Unifier
 
     UnifierSharedState& sharedState;
 
-    Unifier(TypeArena* types, Mode mode, NotNull<Scope> scope, const Location& location, Variance variance, UnifierSharedState& sharedState, TxnLog* parentLog = nullptr);
+    Unifier(TypeArena* types, Mode mode, NotNull<Scope> scope, const Location& location, Variance variance, UnifierSharedState& sharedState,
+        TxnLog* parentLog = nullptr);
 
     // Test whether the two type vars unify.  Never commits the result.
     ErrorVec canUnify(TypeId subTy, TypeId superTy);
diff --git a/Analysis/include/Luau/VisitTypeVar.h b/Analysis/include/Luau/VisitTypeVar.h
index 9d7fa9fe..315e5992 100644
--- a/Analysis/include/Luau/VisitTypeVar.h
+++ b/Analysis/include/Luau/VisitTypeVar.h
@@ -188,6 +188,10 @@ struct GenericTypeVarVisitor
     {
         return visit(tp);
     }
+    virtual bool visit(TypePackId tp, const BlockedTypePack& btp)
+    {
+        return visit(tp);
+    }
 
     void traverse(TypeId ty)
     {
@@ -314,24 +318,6 @@ struct GenericTypeVarVisitor
         {
             if (visit(ty, *petv))
             {
-                traverse(petv->fn.type);
-
-                for (const GenericTypeDefinition& p : petv->fn.typeParams)
-                {
-                    traverse(p.ty);
-
-                    if (p.defaultValue)
-                        traverse(*p.defaultValue);
-                }
-
-                for (const GenericTypePackDefinition& p : petv->fn.typePackParams)
-                {
-                    traverse(p.tp);
-
-                    if (p.defaultValue)
-                        traverse(*p.defaultValue);
-                }
-
                 for (TypeId a : petv->typeArguments)
                     traverse(a);
 
@@ -388,6 +374,9 @@ struct GenericTypeVarVisitor
             if (res)
                 traverse(pack->ty);
         }
+        else if (auto btp = get<BlockedTypePack>(tp))
+            visit(tp, *btp);
+
         else
             LUAU_ASSERT(!"GenericTypeVarVisitor::traverse(TypePackId) is not exhaustive!");
 
diff --git a/Analysis/src/Anyification.cpp b/Analysis/src/Anyification.cpp
index b6e58009..abcaba02 100644
--- a/Analysis/src/Anyification.cpp
+++ b/Analysis/src/Anyification.cpp
@@ -11,15 +11,20 @@ LUAU_FASTFLAG(LuauClassTypeVarsInSubstitution)
 namespace Luau
 {
 
-Anyification::Anyification(TypeArena* arena, const ScopePtr& scope, InternalErrorReporter* iceHandler, TypeId anyType, TypePackId anyTypePack)
+Anyification::Anyification(TypeArena* arena, NotNull<Scope> scope, InternalErrorReporter* iceHandler, TypeId anyType, TypePackId anyTypePack)
     : Substitution(TxnLog::empty(), arena)
-    , scope(NotNull{scope.get()})
+    , scope(scope)
     , iceHandler(iceHandler)
     , anyType(anyType)
     , anyTypePack(anyTypePack)
 {
 }
 
+Anyification::Anyification(TypeArena* arena, const ScopePtr& scope, InternalErrorReporter* iceHandler, TypeId anyType, TypePackId anyTypePack)
+    : Anyification(arena, NotNull{scope.get()}, iceHandler, anyType, anyTypePack)
+{
+}
+
 bool Anyification::isDirty(TypeId ty)
 {
     if (ty->persistent)
@@ -93,4 +98,4 @@ bool Anyification::ignoreChildren(TypePackId ty)
     return ty->persistent;
 }
 
-}
+} // namespace Luau
diff --git a/Analysis/src/Autocomplete.cpp b/Analysis/src/Autocomplete.cpp
index 5c484899..378a1cb7 100644
--- a/Analysis/src/Autocomplete.cpp
+++ b/Analysis/src/Autocomplete.cpp
@@ -1215,8 +1215,8 @@ static bool autocompleteIfElseExpression(
     }
 }
 
-static AutocompleteContext autocompleteExpression(const SourceModule& sourceModule, const Module& module, const TypeChecker& typeChecker, TypeArena* typeArena,
-    const std::vector<AstNode*>& ancestry, Position position, AutocompleteEntryMap& result)
+static AutocompleteContext autocompleteExpression(const SourceModule& sourceModule, const Module& module, const TypeChecker& typeChecker,
+    TypeArena* typeArena, const std::vector<AstNode*>& ancestry, Position position, AutocompleteEntryMap& result)
 {
     LUAU_ASSERT(!ancestry.empty());
 
@@ -1422,8 +1422,8 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
         PropIndexType indexType = indexName->op == ':' ? PropIndexType::Colon : PropIndexType::Point;
 
         if (!FFlag::LuauSelfCallAutocompleteFix3 && isString(ty))
-            return {
-                autocompleteProps(*module, typeArena, typeChecker.globalScope->bindings[AstName{"string"}].typeId, indexType, ancestry), ancestry, AutocompleteContext::Property};
+            return {autocompleteProps(*module, typeArena, typeChecker.globalScope->bindings[AstName{"string"}].typeId, indexType, ancestry), ancestry,
+                AutocompleteContext::Property};
         else
             return {autocompleteProps(*module, typeArena, ty, indexType, ancestry), ancestry, AutocompleteContext::Property};
     }
@@ -1522,8 +1522,8 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
 
     else if (AstStatIf* statIf = node->as<AstStatIf>(); statIf && !statIf->elseLocation.has_value())
     {
-        return {
-            {{"else", AutocompleteEntry{AutocompleteEntryKind::Keyword}}, {"elseif", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
+        return {{{"else", AutocompleteEntry{AutocompleteEntryKind::Keyword}}, {"elseif", AutocompleteEntry{AutocompleteEntryKind::Keyword}}},
+            ancestry, AutocompleteContext::Keyword};
     }
     else if (AstStatIf* statIf = parent->as<AstStatIf>(); statIf && node->is<AstStatBlock>())
     {
diff --git a/Analysis/src/BuiltinDefinitions.cpp b/Analysis/src/BuiltinDefinitions.cpp
index 826179b3..e011eaa5 100644
--- a/Analysis/src/BuiltinDefinitions.cpp
+++ b/Analysis/src/BuiltinDefinitions.cpp
@@ -5,6 +5,7 @@
 #include "Luau/Symbol.h"
 #include "Luau/Common.h"
 #include "Luau/ToString.h"
+#include "Luau/ConstraintSolver.h"
 
 #include <algorithm>
 
@@ -32,6 +33,8 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionPack(
 static std::optional<WithPredicate<TypePackId>> magicFunctionRequire(
     TypeChecker& typechecker, const ScopePtr& scope, const AstExprCall& expr, WithPredicate<TypePackId> withPredicate);
 
+static bool dcrMagicFunctionRequire(NotNull<ConstraintSolver> solver, TypePackId result, const AstExprCall* expr);
+
 TypeId makeUnion(TypeArena& arena, std::vector<TypeId>&& types)
 {
     return arena.addType(UnionTypeVar{std::move(types)});
@@ -105,6 +108,14 @@ void attachMagicFunction(TypeId ty, MagicFunction fn)
         LUAU_ASSERT(!"Got a non functional type");
 }
 
+void attachDcrMagicFunction(TypeId ty, DcrMagicFunction fn)
+{
+    if (auto ftv = getMutable<FunctionTypeVar>(ty))
+        ftv->dcrMagicFunction = fn;
+    else
+        LUAU_ASSERT(!"Got a non functional type");
+}
+
 Property makeProperty(TypeId ty, std::optional<std::string> documentationSymbol)
 {
     return {
@@ -263,6 +274,7 @@ void registerBuiltinTypes(TypeChecker& typeChecker)
     }
 
     attachMagicFunction(getGlobalBinding(typeChecker, "require"), magicFunctionRequire);
+    attachDcrMagicFunction(getGlobalBinding(typeChecker, "require"), dcrMagicFunctionRequire);
 }
 
 static std::optional<WithPredicate<TypePackId>> magicFunctionSelect(
@@ -509,4 +521,49 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionRequire(
     return std::nullopt;
 }
 
+static bool checkRequirePathDcr(NotNull<ConstraintSolver> solver, AstExpr* expr)
+{
+    // require(foo.parent.bar) will technically work, but it depends on legacy goop that
+    // Luau does not and could not support without a bunch of work.  It's deprecated anyway, so
+    // we'll warn here if we see it.
+    bool good = true;
+    AstExprIndexName* indexExpr = expr->as<AstExprIndexName>();
+
+    while (indexExpr)
+    {
+        if (indexExpr->index == "parent")
+        {
+            solver->reportError(DeprecatedApiUsed{"parent", "Parent"}, indexExpr->indexLocation);
+            good = false;
+        }
+
+        indexExpr = indexExpr->expr->as<AstExprIndexName>();
+    }
+
+    return good;
+}
+
+static bool dcrMagicFunctionRequire(NotNull<ConstraintSolver> solver, TypePackId result, const AstExprCall* expr)
+{
+    if (expr->args.size != 1)
+    {
+        solver->reportError(GenericError{"require takes 1 argument"}, expr->location);
+        return false;
+    }
+
+    if (!checkRequirePathDcr(solver, expr->args.data[0]))
+        return false;
+
+    if (auto moduleInfo = solver->moduleResolver->resolveModuleInfo(solver->currentModuleName, *expr))
+    {
+        TypeId moduleType = solver->resolveModule(*moduleInfo, expr->location);
+        TypePackId moduleResult = solver->arena->addTypePack({moduleType});
+        asMutable(result)->ty.emplace<BoundTypePack>(moduleResult);
+
+        return true;
+    }
+
+    return false;
+}
+
 } // namespace Luau
diff --git a/Analysis/src/Clone.cpp b/Analysis/src/Clone.cpp
index 2e04b527..7048d201 100644
--- a/Analysis/src/Clone.cpp
+++ b/Analysis/src/Clone.cpp
@@ -102,6 +102,11 @@ struct TypePackCloner
         defaultClone(t);
     }
 
+    void operator()(const BlockedTypePack& t)
+    {
+        defaultClone(t);
+    }
+
     // While we are a-cloning, we can flatten out bound TypeVars and make things a bit tighter.
     // We just need to be sure that we rewrite pointers both to the binder and the bindee to the same pointer.
     void operator()(const Unifiable::Bound<TypePackId>& t)
@@ -170,7 +175,7 @@ void TypeCloner::operator()(const BlockedTypeVar& t)
 
 void TypeCloner::operator()(const PendingExpansionTypeVar& t)
 {
-    TypeId res = dest.addType(PendingExpansionTypeVar{t.fn, t.typeArguments, t.packArguments});
+    TypeId res = dest.addType(PendingExpansionTypeVar{t.prefix, t.name, t.typeArguments, t.packArguments});
     PendingExpansionTypeVar* petv = getMutable<PendingExpansionTypeVar>(res);
     LUAU_ASSERT(petv);
 
@@ -184,32 +189,6 @@ void TypeCloner::operator()(const PendingExpansionTypeVar& t)
     for (TypePackId arg : t.packArguments)
         packArguments.push_back(clone(arg, dest, cloneState));
 
-    TypeFun fn;
-    fn.type = clone(t.fn.type, dest, cloneState);
-
-    for (const GenericTypeDefinition& param : t.fn.typeParams)
-    {
-        TypeId ty = clone(param.ty, dest, cloneState);
-        std::optional<TypeId> defaultValue = param.defaultValue;
-
-        if (defaultValue)
-            defaultValue = clone(*defaultValue, dest, cloneState);
-
-        fn.typeParams.push_back(GenericTypeDefinition{ty, defaultValue});
-    }
-
-    for (const GenericTypePackDefinition& param : t.fn.typePackParams)
-    {
-        TypePackId tp = clone(param.tp, dest, cloneState);
-        std::optional<TypePackId> defaultValue = param.defaultValue;
-
-        if (defaultValue)
-            defaultValue = clone(*defaultValue, dest, cloneState);
-
-        fn.typePackParams.push_back(GenericTypePackDefinition{tp, defaultValue});
-    }
-
-    petv->fn = std::move(fn);
     petv->typeArguments = std::move(typeArguments);
     petv->packArguments = std::move(packArguments);
 }
@@ -461,6 +440,7 @@ TypeId shallowClone(TypeId ty, TypeArena& dest, const TxnLog* log, bool alwaysCl
         clone.generics = ftv->generics;
         clone.genericPacks = ftv->genericPacks;
         clone.magicFunction = ftv->magicFunction;
+        clone.dcrMagicFunction = ftv->dcrMagicFunction;
         clone.tags = ftv->tags;
         clone.argNames = ftv->argNames;
         result = dest.addType(std::move(clone));
@@ -502,7 +482,7 @@ TypeId shallowClone(TypeId ty, TypeArena& dest, const TxnLog* log, bool alwaysCl
     }
     else if (const PendingExpansionTypeVar* petv = get<PendingExpansionTypeVar>(ty))
     {
-        PendingExpansionTypeVar clone{petv->fn, petv->typeArguments, petv->packArguments};
+        PendingExpansionTypeVar clone{petv->prefix, petv->name, petv->typeArguments, petv->packArguments};
         result = dest.addType(std::move(clone));
     }
     else if (const ClassTypeVar* ctv = get<ClassTypeVar>(ty); FFlag::LuauClonePublicInterfaceLess && ctv && alwaysClone)
diff --git a/Analysis/src/Constraint.cpp b/Analysis/src/Constraint.cpp
index d272c027..3a6417dc 100644
--- a/Analysis/src/Constraint.cpp
+++ b/Analysis/src/Constraint.cpp
@@ -5,9 +5,10 @@
 namespace Luau
 {
 
-Constraint::Constraint(ConstraintV&& c, NotNull<Scope> scope)
-    : c(std::move(c))
-    , scope(scope)
+Constraint::Constraint(NotNull<Scope> scope, const Location& location, ConstraintV&& c)
+    : scope(scope)
+    , location(location)
+    , c(std::move(c))
 {
 }
 
diff --git a/Analysis/src/ConstraintGraphBuilder.cpp b/Analysis/src/ConstraintGraphBuilder.cpp
index 8f994740..9fabc528 100644
--- a/Analysis/src/ConstraintGraphBuilder.cpp
+++ b/Analysis/src/ConstraintGraphBuilder.cpp
@@ -4,6 +4,7 @@
 #include "Luau/Ast.h"
 #include "Luau/Common.h"
 #include "Luau/Constraint.h"
+#include "Luau/ModuleResolver.h"
 #include "Luau/RecursionCounter.h"
 #include "Luau/ToString.h"
 
@@ -16,13 +17,31 @@ namespace Luau
 
 const AstStat* getFallthrough(const AstStat* node); // TypeInfer.cpp
 
-ConstraintGraphBuilder::ConstraintGraphBuilder(
-    const ModuleName& moduleName, ModulePtr module, TypeArena* arena, NotNull<InternalErrorReporter> ice, const ScopePtr& globalScope)
+static std::optional<AstExpr*> matchRequire(const AstExprCall& call)
+{
+    const char* require = "require";
+
+    if (call.args.size != 1)
+        return std::nullopt;
+
+    const AstExprGlobal* funcAsGlobal = call.func->as<AstExprGlobal>();
+    if (!funcAsGlobal || funcAsGlobal->name != require)
+        return std::nullopt;
+
+    if (call.args.size != 1)
+        return std::nullopt;
+
+    return call.args.data[0];
+}
+
+ConstraintGraphBuilder::ConstraintGraphBuilder(const ModuleName& moduleName, ModulePtr module, TypeArena* arena,
+    NotNull<ModuleResolver> moduleResolver, NotNull<InternalErrorReporter> ice, const ScopePtr& globalScope)
     : moduleName(moduleName)
     , module(module)
     , singletonTypes(getSingletonTypes())
     , arena(arena)
     , rootScope(nullptr)
+    , moduleResolver(moduleResolver)
     , ice(ice)
     , globalScope(globalScope)
 {
@@ -54,9 +73,9 @@ ScopePtr ConstraintGraphBuilder::childScope(AstNode* node, const ScopePtr& paren
     return scope;
 }
 
-void ConstraintGraphBuilder::addConstraint(const ScopePtr& scope, ConstraintV cv)
+void ConstraintGraphBuilder::addConstraint(const ScopePtr& scope, const Location& location, ConstraintV cv)
 {
-    scope->constraints.emplace_back(new Constraint{std::move(cv), NotNull{scope.get()}});
+    scope->constraints.emplace_back(new Constraint{NotNull{scope.get()}, location, std::move(cv)});
 }
 
 void ConstraintGraphBuilder::addConstraint(const ScopePtr& scope, std::unique_ptr<Constraint> c)
@@ -77,13 +96,6 @@ void ConstraintGraphBuilder::visit(AstStatBlock* block)
 
     prepopulateGlobalScope(scope, block);
 
-    // TODO: We should share the global scope.
-    rootScope->privateTypeBindings["nil"] = TypeFun{singletonTypes.nilType};
-    rootScope->privateTypeBindings["number"] = TypeFun{singletonTypes.numberType};
-    rootScope->privateTypeBindings["string"] = TypeFun{singletonTypes.stringType};
-    rootScope->privateTypeBindings["boolean"] = TypeFun{singletonTypes.booleanType};
-    rootScope->privateTypeBindings["thread"] = TypeFun{singletonTypes.threadType};
-
     visitBlockWithoutChildScope(scope, block);
 }
 
@@ -158,6 +170,8 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStat* stat)
         visit(scope, s);
     else if (auto s = stat->as<AstStatFor>())
         visit(scope, s);
+    else if (auto s = stat->as<AstStatForIn>())
+        visit(scope, s);
     else if (auto s = stat->as<AstStatWhile>())
         visit(scope, s);
     else if (auto s = stat->as<AstStatRepeat>())
@@ -201,7 +215,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocal* local)
         {
             location = local->annotation->location;
             TypeId annotation = resolveType(scope, local->annotation, /* topLevel */ true);
-            addConstraint(scope, SubtypeConstraint{ty, annotation});
+            addConstraint(scope, location, SubtypeConstraint{ty, annotation});
         }
 
         varTypes.push_back(ty);
@@ -225,14 +239,38 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocal* local)
             {
                 std::vector<TypeId> tailValues{varTypes.begin() + i, varTypes.end()};
                 TypePackId tailPack = arena->addTypePack(std::move(tailValues));
-                addConstraint(scope, PackSubtypeConstraint{exprPack, tailPack});
+                addConstraint(scope, local->location, PackSubtypeConstraint{exprPack, tailPack});
             }
         }
         else
         {
             TypeId exprType = check(scope, value);
             if (i < varTypes.size())
-                addConstraint(scope, SubtypeConstraint{varTypes[i], exprType});
+                addConstraint(scope, local->location, SubtypeConstraint{varTypes[i], exprType});
+        }
+    }
+
+    if (local->values.size > 0)
+    {
+        // To correctly handle 'require', we need to import the exported type bindings into the variable 'namespace'.
+        for (size_t i = 0; i < local->values.size && i < local->vars.size; ++i)
+        {
+            const AstExprCall* call = local->values.data[i]->as<AstExprCall>();
+            if (!call)
+                continue;
+
+            if (auto maybeRequire = matchRequire(*call))
+            {
+                AstExpr* require = *maybeRequire;
+
+                if (auto moduleInfo = moduleResolver->resolveModuleInfo(moduleName, *require))
+                {
+                    const Name name{local->vars.data[i]->name.value};
+
+                    if (ModulePtr module = moduleResolver->getModule(moduleInfo->name))
+                        scope->importedTypeBindings[name] = module->getModuleScope()->exportedTypeBindings;
+                }
+            }
         }
     }
 }
@@ -244,7 +282,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFor* for_)
             return;
 
         TypeId t = check(scope, expr);
-        addConstraint(scope, SubtypeConstraint{t, singletonTypes.numberType});
+        addConstraint(scope, expr->location, SubtypeConstraint{t, singletonTypes.numberType});
     };
 
     checkNumber(for_->from);
@@ -257,6 +295,29 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFor* for_)
     visit(forScope, for_->body);
 }
 
+void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatForIn* forIn)
+{
+    ScopePtr loopScope = childScope(forIn, scope);
+
+    TypePackId iterator = checkPack(scope, forIn->values);
+
+    std::vector<TypeId> variableTypes;
+    variableTypes.reserve(forIn->vars.size);
+    for (AstLocal* var : forIn->vars)
+    {
+        TypeId ty = freshType(loopScope);
+        loopScope->bindings[var] = Binding{ty, var->location};
+        variableTypes.push_back(ty);
+    }
+
+    // It is always ok to provide too few variables, so we give this pack a free tail.
+    TypePackId variablePack = arena->addTypePack(std::move(variableTypes), arena->addTypePack(FreeTypePack{loopScope.get()}));
+
+    addConstraint(loopScope, getLocation(forIn->values), IterableConstraint{iterator, variablePack});
+
+    visit(loopScope, forIn->body);
+}
+
 void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatWhile* while_)
 {
     check(scope, while_->condition);
@@ -284,6 +345,9 @@ void addConstraints(Constraint* constraint, NotNull<Scope> scope)
     for (const auto& c : scope->constraints)
         constraint->dependencies.push_back(NotNull{c.get()});
 
+    for (const auto& c : scope->unqueuedConstraints)
+        constraint->dependencies.push_back(NotNull{c.get()});
+
     for (NotNull<Scope> childScope : scope->children)
         addConstraints(constraint, childScope);
 }
@@ -308,7 +372,8 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocalFunction*
     checkFunctionBody(sig.bodyScope, function->func);
 
     NotNull<Scope> constraintScope{sig.signatureScope ? sig.signatureScope.get() : sig.bodyScope.get()};
-    std::unique_ptr<Constraint> c = std::make_unique<Constraint>(GeneralizationConstraint{functionType, sig.signature}, constraintScope);
+    std::unique_ptr<Constraint> c =
+        std::make_unique<Constraint>(constraintScope, function->name->location, GeneralizationConstraint{functionType, sig.signature});
     addConstraints(c.get(), NotNull(sig.bodyScope.get()));
 
     addConstraint(scope, std::move(c));
@@ -366,7 +431,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFunction* funct
         prop.type = functionType;
         prop.location = function->name->location;
 
-        addConstraint(scope, SubtypeConstraint{containingTableType, prospectiveTableType});
+        addConstraint(scope, indexName->location, SubtypeConstraint{containingTableType, prospectiveTableType});
     }
     else if (AstExprError* err = function->name->as<AstExprError>())
     {
@@ -378,7 +443,8 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFunction* funct
     checkFunctionBody(sig.bodyScope, function->func);
 
     NotNull<Scope> constraintScope{sig.signatureScope ? sig.signatureScope.get() : sig.bodyScope.get()};
-    std::unique_ptr<Constraint> c = std::make_unique<Constraint>(GeneralizationConstraint{functionType, sig.signature}, constraintScope);
+    std::unique_ptr<Constraint> c =
+        std::make_unique<Constraint>(constraintScope, function->name->location, GeneralizationConstraint{functionType, sig.signature});
     addConstraints(c.get(), NotNull(sig.bodyScope.get()));
 
     addConstraint(scope, std::move(c));
@@ -387,7 +453,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFunction* funct
 void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatReturn* ret)
 {
     TypePackId exprTypes = checkPack(scope, ret->list);
-    addConstraint(scope, PackSubtypeConstraint{exprTypes, scope->returnType});
+    addConstraint(scope, ret->location, PackSubtypeConstraint{exprTypes, scope->returnType});
 }
 
 void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatBlock* block)
@@ -399,10 +465,10 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatBlock* block)
 
 void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatAssign* assign)
 {
-    TypePackId varPackId = checkExprList(scope, assign->vars);
+    TypePackId varPackId = checkPack(scope, assign->vars);
     TypePackId valuePack = checkPack(scope, assign->values);
 
-    addConstraint(scope, PackSubtypeConstraint{valuePack, varPackId});
+    addConstraint(scope, assign->location, PackSubtypeConstraint{valuePack, varPackId});
 }
 
 void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatCompoundAssign* assign)
@@ -435,8 +501,6 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatIf* ifStatement
 
 void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatTypeAlias* alias)
 {
-    // TODO: Exported type aliases
-
     auto bindingIt = scope->privateTypeBindings.find(alias->name.value);
     ScopePtr* defnIt = astTypeAliasDefiningScopes.find(alias);
     // These will be undefined if the alias was a duplicate definition, in which
@@ -449,6 +513,12 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatTypeAlias* alia
     ScopePtr resolvingScope = *defnIt;
     TypeId ty = resolveType(resolvingScope, alias->type, /* topLevel */ true);
 
+    if (alias->exported)
+    {
+        Name typeName(alias->name.value);
+        scope->exportedTypeBindings[typeName] = TypeFun{ty};
+    }
+
     LUAU_ASSERT(get<FreeTypeVar>(bindingIt->second.type));
 
     // Rather than using a subtype constraint, we instead directly bind
@@ -457,7 +527,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatTypeAlias* alia
     // bind the free alias type to an unrelated type, causing havoc.
     asMutable(bindingIt->second.type)->ty.emplace<BoundTypeVar>(ty);
 
-    addConstraint(scope, NameConstraint{ty, alias->name.value});
+    addConstraint(scope, alias->location, NameConstraint{ty, alias->name.value});
 }
 
 void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareGlobal* global)
@@ -615,44 +685,22 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareFunction
 
 TypePackId ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstArray<AstExpr*> exprs)
 {
-    if (exprs.size == 0)
-        return arena->addTypePack({});
-
-    std::vector<TypeId> types;
-    TypePackId last = nullptr;
-
-    for (size_t i = 0; i < exprs.size; ++i)
-    {
-        if (i < exprs.size - 1)
-            types.push_back(check(scope, exprs.data[i]));
-        else
-            last = checkPack(scope, exprs.data[i]);
-    }
-
-    LUAU_ASSERT(last != nullptr);
-
-    return arena->addTypePack(TypePack{std::move(types), last});
-}
-
-TypePackId ConstraintGraphBuilder::checkExprList(const ScopePtr& scope, const AstArray<AstExpr*>& exprs)
-{
-    TypePackId result = arena->addTypePack({});
-    TypePack* resultPack = getMutable<TypePack>(result);
-    LUAU_ASSERT(resultPack);
+    std::vector<TypeId> head;
+    std::optional<TypePackId> tail;
 
     for (size_t i = 0; i < exprs.size; ++i)
     {
         AstExpr* expr = exprs.data[i];
         if (i < exprs.size - 1)
-            resultPack->head.push_back(check(scope, expr));
+            head.push_back(check(scope, expr));
         else
-            resultPack->tail = checkPack(scope, expr);
+            tail = checkPack(scope, expr);
     }
 
-    if (resultPack->head.empty() && resultPack->tail)
-        return *resultPack->tail;
+    if (head.empty() && tail)
+        return *tail;
     else
-        return result;
+        return arena->addTypePack(TypePack{std::move(head), tail});
 }
 
 TypePackId ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExpr* expr)
@@ -683,13 +731,26 @@ TypePackId ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExpr* exp
         astOriginalCallTypes[call->func] = fnType;
 
         TypeId instantiatedType = arena->addType(BlockedTypeVar{});
-        addConstraint(scope, InstantiationConstraint{instantiatedType, fnType});
-
-        TypePackId rets = freshTypePack(scope);
+        TypePackId rets = arena->addTypePack(BlockedTypePack{});
         FunctionTypeVar ftv(arena->addTypePack(TypePack{args, {}}), rets);
         TypeId inferredFnType = arena->addType(ftv);
 
-        addConstraint(scope, SubtypeConstraint{inferredFnType, instantiatedType});
+        scope->unqueuedConstraints.push_back(
+            std::make_unique<Constraint>(NotNull{scope.get()}, call->func->location, InstantiationConstraint{instantiatedType, fnType}));
+        NotNull<const Constraint> ic(scope->unqueuedConstraints.back().get());
+
+        scope->unqueuedConstraints.push_back(
+            std::make_unique<Constraint>(NotNull{scope.get()}, call->func->location, SubtypeConstraint{inferredFnType, instantiatedType}));
+        NotNull<const Constraint> sc(scope->unqueuedConstraints.back().get());
+
+        addConstraint(scope, call->func->location,
+            FunctionCallConstraint{
+                {ic, sc},
+                fnType,
+                rets,
+                call,
+            });
+
         result = rets;
     }
     else if (AstExprVarargs* varargs = expr->as<AstExprVarargs>())
@@ -805,7 +866,7 @@ TypeId ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIndexName* in
 
     TypeId expectedTableType = arena->addType(std::move(ttv));
 
-    addConstraint(scope, SubtypeConstraint{obj, expectedTableType});
+    addConstraint(scope, indexName->expr->location, SubtypeConstraint{obj, expectedTableType});
 
     return result;
 }
@@ -820,7 +881,7 @@ TypeId ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIndexExpr* in
     TableIndexer indexer{indexType, result};
     TypeId tableType = arena->addType(TableTypeVar{TableTypeVar::Props{}, TableIndexer{indexType, result}, TypeLevel{}, TableState::Free});
 
-    addConstraint(scope, SubtypeConstraint{obj, tableType});
+    addConstraint(scope, indexExpr->expr->location, SubtypeConstraint{obj, tableType});
 
     return result;
 }
@@ -834,7 +895,7 @@ TypeId ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprUnary* unary)
     case AstExprUnary::Minus:
     {
         TypeId resultType = arena->addType(BlockedTypeVar{});
-        addConstraint(scope, UnaryConstraint{AstExprUnary::Minus, operandType, resultType});
+        addConstraint(scope, unary->location, UnaryConstraint{AstExprUnary::Minus, operandType, resultType});
         return resultType;
     }
     default:
@@ -853,19 +914,19 @@ TypeId ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprBinary* binar
     {
     case AstExprBinary::Or:
     {
-        addConstraint(scope, SubtypeConstraint{leftType, rightType});
+        addConstraint(scope, binary->location, SubtypeConstraint{leftType, rightType});
         return leftType;
     }
     case AstExprBinary::Add:
     {
         TypeId resultType = arena->addType(BlockedTypeVar{});
-        addConstraint(scope, BinaryConstraint{AstExprBinary::Add, leftType, rightType, resultType});
+        addConstraint(scope, binary->location, BinaryConstraint{AstExprBinary::Add, leftType, rightType, resultType});
         return resultType;
     }
     case AstExprBinary::Sub:
     {
         TypeId resultType = arena->addType(BlockedTypeVar{});
-        addConstraint(scope, BinaryConstraint{AstExprBinary::Sub, leftType, rightType, resultType});
+        addConstraint(scope, binary->location, BinaryConstraint{AstExprBinary::Sub, leftType, rightType, resultType});
         return resultType;
     }
     default:
@@ -886,8 +947,8 @@ TypeId ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIfElse* ifEls
     if (ifElse->hasElse)
     {
         TypeId resultType = arena->addType(BlockedTypeVar{});
-        addConstraint(scope, SubtypeConstraint{thenType, resultType});
-        addConstraint(scope, SubtypeConstraint{elseType, resultType});
+        addConstraint(scope, ifElse->trueExpr->location, SubtypeConstraint{thenType, resultType});
+        addConstraint(scope, ifElse->falseExpr->location, SubtypeConstraint{elseType, resultType});
         return resultType;
     }
 
@@ -906,7 +967,7 @@ TypeId ConstraintGraphBuilder::checkExprTable(const ScopePtr& scope, AstExprTabl
     TableTypeVar* ttv = getMutable<TableTypeVar>(ty);
     LUAU_ASSERT(ttv);
 
-    auto createIndexer = [this, scope, ttv](TypeId currentIndexType, TypeId currentResultType) {
+    auto createIndexer = [this, scope, ttv](const Location& location, TypeId currentIndexType, TypeId currentResultType) {
         if (!ttv->indexer)
         {
             TypeId indexType = this->freshType(scope);
@@ -914,8 +975,8 @@ TypeId ConstraintGraphBuilder::checkExprTable(const ScopePtr& scope, AstExprTabl
             ttv->indexer = TableIndexer{indexType, resultType};
         }
 
-        addConstraint(scope, SubtypeConstraint{ttv->indexer->indexType, currentIndexType});
-        addConstraint(scope, SubtypeConstraint{ttv->indexer->indexResultType, currentResultType});
+        addConstraint(scope, location, SubtypeConstraint{ttv->indexer->indexType, currentIndexType});
+        addConstraint(scope, location, SubtypeConstraint{ttv->indexer->indexResultType, currentResultType});
     };
 
     for (const AstExprTable::Item& item : expr->items)
@@ -937,13 +998,15 @@ TypeId ConstraintGraphBuilder::checkExprTable(const ScopePtr& scope, AstExprTabl
             }
             else
             {
-                createIndexer(keyTy, itemTy);
+                createIndexer(item.key->location, keyTy, itemTy);
             }
         }
         else
         {
             TypeId numberType = singletonTypes.numberType;
-            createIndexer(numberType, itemTy);
+            // FIXME?  The location isn't quite right here.  Not sure what is
+            // right.
+            createIndexer(item.value->location, numberType, itemTy);
         }
     }
 
@@ -1008,7 +1071,7 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS
     if (fn->returnAnnotation)
     {
         TypePackId annotatedRetType = resolveTypePack(signatureScope, *fn->returnAnnotation);
-        addConstraint(signatureScope, PackSubtypeConstraint{returnType, annotatedRetType});
+        addConstraint(signatureScope, getLocation(*fn->returnAnnotation), PackSubtypeConstraint{returnType, annotatedRetType});
     }
 
     std::vector<TypeId> argTypes;
@@ -1022,7 +1085,7 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS
         if (local->annotation)
         {
             TypeId argAnnotation = resolveType(signatureScope, local->annotation, /* topLevel */ true);
-            addConstraint(signatureScope, SubtypeConstraint{t, argAnnotation});
+            addConstraint(signatureScope, local->annotation->location, SubtypeConstraint{t, argAnnotation});
         }
     }
 
@@ -1056,7 +1119,7 @@ void ConstraintGraphBuilder::checkFunctionBody(const ScopePtr& scope, AstExprFun
     if (nullptr != getFallthrough(fn->body))
     {
         TypePackId empty = arena->addTypePack({}); // TODO we could have CSG retain one of these forever
-        addConstraint(scope, PackSubtypeConstraint{scope->returnType, empty});
+        addConstraint(scope, fn->location, PackSubtypeConstraint{scope->returnType, empty});
     }
 }
 
@@ -1066,16 +1129,13 @@ TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, b
 
     if (auto ref = ty->as<AstTypeReference>())
     {
-        // TODO: Support imported types w/ require tracing.
-        LUAU_ASSERT(!ref->prefix);
-
         std::optional<TypeFun> alias = scope->lookupType(ref->name.value);
 
-        if (alias.has_value())
+        if (alias.has_value() || ref->prefix.has_value())
         {
             // If the alias is not generic, we don't need to set up a blocked
             // type and an instantiation constraint.
-            if (alias->typeParams.empty() && alias->typePackParams.empty())
+            if (alias.has_value() && alias->typeParams.empty() && alias->typePackParams.empty())
             {
                 result = alias->type;
             }
@@ -1104,11 +1164,11 @@ TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, b
                     }
                 }
 
-                result = arena->addType(PendingExpansionTypeVar{*alias, parameters, packParameters});
+                result = arena->addType(PendingExpansionTypeVar{ref->prefix, ref->name, parameters, packParameters});
 
                 if (topLevel)
                 {
-                    addConstraint(scope, TypeAliasExpansionConstraint{ /* target */ result });
+                    addConstraint(scope, ty->location, TypeAliasExpansionConstraint{/* target */ result});
                 }
             }
         }
@@ -1141,8 +1201,7 @@ TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, b
             };
         }
 
-        // TODO: Remove TypeLevel{} here, we don't need it.
-        result = arena->addType(TableTypeVar{props, indexer, TypeLevel{}, TableState::Sealed});
+        result = arena->addType(TableTypeVar{props, indexer, scope->level, TableState::Sealed});
     }
     else if (auto fn = ty->as<AstTypeFunction>())
     {
@@ -1363,7 +1422,7 @@ TypeId ConstraintGraphBuilder::flattenPack(const ScopePtr& scope, Location locat
     TypePack onePack{{typeResult}, freshTypePack(scope)};
     TypePackId oneTypePack = arena->addTypePack(std::move(onePack));
 
-    addConstraint(scope, PackSubtypeConstraint{tp, oneTypePack});
+    addConstraint(scope, location, PackSubtypeConstraint{tp, oneTypePack});
 
     return typeResult;
 }
diff --git a/Analysis/src/ConstraintSolver.cpp b/Analysis/src/ConstraintSolver.cpp
index b2b1d472..1088d982 100644
--- a/Analysis/src/ConstraintSolver.cpp
+++ b/Analysis/src/ConstraintSolver.cpp
@@ -1,9 +1,11 @@
 // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
 
+#include "Luau/Anyification.h"
 #include "Luau/ApplyTypeFunction.h"
 #include "Luau/ConstraintSolver.h"
 #include "Luau/Instantiation.h"
 #include "Luau/Location.h"
+#include "Luau/ModuleResolver.h"
 #include "Luau/Quantify.h"
 #include "Luau/ToString.h"
 #include "Luau/Unifier.h"
@@ -240,11 +242,17 @@ void dump(ConstraintSolver* cs, ToStringOptions& opts)
     }
 }
 
-ConstraintSolver::ConstraintSolver(TypeArena* arena, NotNull<Scope> rootScope)
+ConstraintSolver::ConstraintSolver(TypeArena* arena, NotNull<Scope> rootScope, ModuleName moduleName, NotNull<ModuleResolver> moduleResolver,
+    std::vector<RequireCycle> requireCycles)
     : arena(arena)
     , constraints(collectConstraints(rootScope))
     , rootScope(rootScope)
+    , currentModuleName(std::move(moduleName))
+    , moduleResolver(moduleResolver)
+    , requireCycles(requireCycles)
 {
+    opts.exhaustive = true;
+
     for (NotNull<Constraint> c : constraints)
     {
         unsolvedConstraints.push_back(c);
@@ -261,9 +269,6 @@ void ConstraintSolver::run()
     if (done())
         return;
 
-    ToStringOptions opts;
-    opts.exhaustive = true;
-
     if (FFlag::DebugLuauLogSolver)
     {
         printf("Starting solver\n");
@@ -371,10 +376,14 @@ bool ConstraintSolver::tryDispatch(NotNull<const Constraint> constraint, bool fo
         success = tryDispatch(*uc, constraint, force);
     else if (auto bc = get<BinaryConstraint>(*constraint))
         success = tryDispatch(*bc, constraint, force);
+    else if (auto ic = get<IterableConstraint>(*constraint))
+        success = tryDispatch(*ic, constraint, force);
     else if (auto nc = get<NameConstraint>(*constraint))
         success = tryDispatch(*nc, constraint);
     else if (auto taec = get<TypeAliasExpansionConstraint>(*constraint))
         success = tryDispatch(*taec, constraint);
+    else if (auto fcc = get<FunctionCallConstraint>(*constraint))
+        success = tryDispatch(*fcc, constraint);
     else
         LUAU_ASSERT(0);
 
@@ -400,6 +409,11 @@ bool ConstraintSolver::tryDispatch(const SubtypeConstraint& c, NotNull<const Con
 
 bool ConstraintSolver::tryDispatch(const PackSubtypeConstraint& c, NotNull<const Constraint> constraint, bool force)
 {
+    if (isBlocked(c.subPack))
+        return block(c.subPack, constraint);
+    else if (isBlocked(c.superPack))
+        return block(c.superPack, constraint);
+
     unify(c.subPack, c.superPack, constraint->scope);
     return true;
 }
@@ -512,6 +526,82 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
     return true;
 }
 
+bool ConstraintSolver::tryDispatch(const IterableConstraint& c, NotNull<const Constraint> constraint, bool force)
+{
+    /*
+     * for .. in loops can play out in a bunch of different ways depending on
+     * the shape of iteratee.
+     *
+     * iteratee might be:
+     *  * (nextFn)
+     *  * (nextFn, table)
+     *  * (nextFn, table, firstIndex)
+     *  * table with a metatable and __index
+     *  * table with a metatable and __call but no __index (if the metatable has
+     *    both, __index takes precedence)
+     *  * table with an indexer but no __index or __call (or no metatable)
+     *
+     * To dispatch this constraint, we need first to know enough about iteratee
+     * to figure out which of the above shapes we are actually working with.
+     *
+     * If `force` is true and we still do not know, we must flag a warning. Type
+     * families are the fix for this.
+     *
+     * Since we need to know all of this stuff about the types of the iteratee,
+     * we have no choice but for ConstraintSolver to also be the thing that
+     * applies constraints to the types of the iterators.
+     */
+
+    auto block_ = [&](auto&& t) {
+        if (force)
+        {
+            // If we haven't figured out the type of the iteratee by now,
+            // there's nothing we can do.
+            return true;
+        }
+
+        block(t, constraint);
+        return false;
+    };
+
+    auto [iteratorTypes, iteratorTail] = flatten(c.iterator);
+    if (iteratorTail)
+        return block_(*iteratorTail);
+
+    if (0 == iteratorTypes.size())
+    {
+        Anyification anyify{
+            arena, constraint->scope, &iceReporter, getSingletonTypes().errorRecoveryType(), getSingletonTypes().errorRecoveryTypePack()};
+        std::optional<TypePackId> anyified = anyify.substitute(c.variables);
+        LUAU_ASSERT(anyified);
+        unify(*anyified, c.variables, constraint->scope);
+
+        return true;
+    }
+
+    TypeId nextTy = follow(iteratorTypes[0]);
+    if (get<FreeTypeVar>(nextTy))
+        return block_(nextTy);
+
+    if (get<FunctionTypeVar>(nextTy))
+    {
+        TypeId tableTy = getSingletonTypes().nilType;
+        if (iteratorTypes.size() >= 2)
+            tableTy = iteratorTypes[1];
+
+        TypeId firstIndexTy = getSingletonTypes().nilType;
+        if (iteratorTypes.size() >= 3)
+            firstIndexTy = iteratorTypes[2];
+
+        return tryDispatchIterableFunction(nextTy, tableTy, firstIndexTy, c, constraint, force);
+    }
+
+    else
+        return tryDispatchIterableTable(iteratorTypes[0], c, constraint, force);
+
+    return true;
+}
+
 bool ConstraintSolver::tryDispatch(const NameConstraint& c, NotNull<const Constraint> constraint)
 {
     if (isBlocked(c.namedType))
@@ -519,7 +609,7 @@ bool ConstraintSolver::tryDispatch(const NameConstraint& c, NotNull<const Constr
 
     TypeId target = follow(c.namedType);
 
-    if (target->persistent)
+    if (target->persistent || target->owningArena != arena)
         return true;
 
     if (TableTypeVar* ttv = getMutable<TableTypeVar>(target))
@@ -536,19 +626,27 @@ struct InfiniteTypeFinder : TypeVarOnceVisitor
 {
     ConstraintSolver* solver;
     const InstantiationSignature& signature;
+    NotNull<Scope> scope;
     bool foundInfiniteType = false;
 
-    explicit InfiniteTypeFinder(ConstraintSolver* solver, const InstantiationSignature& signature)
+    explicit InfiniteTypeFinder(ConstraintSolver* solver, const InstantiationSignature& signature, NotNull<Scope> scope)
         : solver(solver)
         , signature(signature)
+        , scope(scope)
     {
     }
 
     bool visit(TypeId ty, const PendingExpansionTypeVar& petv) override
     {
-        auto [typeArguments, packArguments] = saturateArguments(petv.fn, petv.typeArguments, petv.packArguments, solver->arena);
+        std::optional<TypeFun> tf =
+            (petv.prefix) ? scope->lookupImportedType(petv.prefix->value, petv.name.value) : scope->lookupType(petv.name.value);
 
-        if (follow(petv.fn.type) == follow(signature.fn.type) && (signature.arguments != typeArguments || signature.packArguments != packArguments))
+        if (!tf.has_value())
+            return true;
+
+        auto [typeArguments, packArguments] = saturateArguments(*tf, petv.typeArguments, petv.packArguments, solver->arena);
+
+        if (follow(tf->type) == follow(signature.fn.type) && (signature.arguments != typeArguments || signature.packArguments != packArguments))
         {
             foundInfiniteType = true;
             return false;
@@ -563,17 +661,19 @@ struct InstantiationQueuer : TypeVarOnceVisitor
     ConstraintSolver* solver;
     const InstantiationSignature& signature;
     NotNull<Scope> scope;
+    Location location;
 
-    explicit InstantiationQueuer(ConstraintSolver* solver, const InstantiationSignature& signature, NotNull<Scope> scope)
+    explicit InstantiationQueuer(NotNull<Scope> scope, const Location& location, ConstraintSolver* solver, const InstantiationSignature& signature)
         : solver(solver)
         , signature(signature)
         , scope(scope)
+        , location(location)
     {
     }
 
     bool visit(TypeId ty, const PendingExpansionTypeVar& petv) override
     {
-        solver->pushConstraint(TypeAliasExpansionConstraint{ty}, scope);
+        solver->pushConstraint(scope, location, TypeAliasExpansionConstraint{ty});
         return false;
     }
 };
@@ -592,23 +692,32 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
         unblock(c.target);
     };
 
-    // If there are no parameters to the type function we can just use the type
-    // directly.
-    if (petv->fn.typeParams.empty() && petv->fn.typePackParams.empty())
+    std::optional<TypeFun> tf = (petv->prefix) ? constraint->scope->lookupImportedType(petv->prefix->value, petv->name.value)
+                                               : constraint->scope->lookupType(petv->name.value);
+
+    if (!tf.has_value())
     {
-        bindResult(petv->fn.type);
+        reportError(UnknownSymbol{petv->name.value, UnknownSymbol::Context::Type}, constraint->location);
+        bindResult(getSingletonTypes().errorRecoveryType());
         return true;
     }
 
-    auto [typeArguments, packArguments] = saturateArguments(petv->fn, petv->typeArguments, petv->packArguments, arena);
+    // If there are no parameters to the type function we can just use the type
+    // directly.
+    if (tf->typeParams.empty() && tf->typePackParams.empty())
+    {
+        bindResult(tf->type);
+        return true;
+    }
 
-    bool sameTypes =
-        std::equal(typeArguments.begin(), typeArguments.end(), petv->fn.typeParams.begin(), petv->fn.typeParams.end(), [](auto&& itp, auto&& p) {
-            return itp == p.ty;
-        });
+    auto [typeArguments, packArguments] = saturateArguments(*tf, petv->typeArguments, petv->packArguments, arena);
 
-    bool samePacks = std::equal(
-        packArguments.begin(), packArguments.end(), petv->fn.typePackParams.begin(), petv->fn.typePackParams.end(), [](auto&& itp, auto&& p) {
+    bool sameTypes = std::equal(typeArguments.begin(), typeArguments.end(), tf->typeParams.begin(), tf->typeParams.end(), [](auto&& itp, auto&& p) {
+        return itp == p.ty;
+    });
+
+    bool samePacks =
+        std::equal(packArguments.begin(), packArguments.end(), tf->typePackParams.begin(), tf->typePackParams.end(), [](auto&& itp, auto&& p) {
             return itp == p.tp;
         });
 
@@ -617,12 +726,12 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
     // to the TypeFun's type.
     if (sameTypes && samePacks)
     {
-        bindResult(petv->fn.type);
+        bindResult(tf->type);
         return true;
     }
 
     InstantiationSignature signature{
-        petv->fn,
+        *tf,
         typeArguments,
         packArguments,
     };
@@ -642,8 +751,8 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
     // https://github.com/Roblox/luau/pull/68 for the RFC responsible for this.
     // This is a little nicer than using a recursion limit because we can catch
     // the infinite expansion before actually trying to expand it.
-    InfiniteTypeFinder itf{this, signature};
-    itf.traverse(petv->fn.type);
+    InfiniteTypeFinder itf{this, signature, constraint->scope};
+    itf.traverse(tf->type);
 
     if (itf.foundInfiniteType)
     {
@@ -655,15 +764,15 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
     ApplyTypeFunction applyTypeFunction{arena};
     for (size_t i = 0; i < typeArguments.size(); ++i)
     {
-        applyTypeFunction.typeArguments[petv->fn.typeParams[i].ty] = typeArguments[i];
+        applyTypeFunction.typeArguments[tf->typeParams[i].ty] = typeArguments[i];
     }
 
     for (size_t i = 0; i < packArguments.size(); ++i)
     {
-        applyTypeFunction.typePackArguments[petv->fn.typePackParams[i].tp] = packArguments[i];
+        applyTypeFunction.typePackArguments[tf->typePackParams[i].tp] = packArguments[i];
     }
 
-    std::optional<TypeId> maybeInstantiated = applyTypeFunction.substitute(petv->fn.type);
+    std::optional<TypeId> maybeInstantiated = applyTypeFunction.substitute(tf->type);
     // Note that ApplyTypeFunction::encounteredForwardedType is never set in
     // DCR, because we do not use free types for forward-declared generic
     // aliases.
@@ -683,7 +792,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
 
     // Type function application will happily give us the exact same type if
     // there are e.g. generic saturatedTypeArguments that go unused.
-    bool needsClone = follow(petv->fn.type) == target;
+    bool needsClone = follow(tf->type) == target;
     // Only tables have the properties we're trying to set.
     TableTypeVar* ttv = getMutableTableType(target);
 
@@ -722,7 +831,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
     // The application is not recursive, so we need to queue up application of
     // any child type function instantiations within the result in order for it
     // to be complete.
-    InstantiationQueuer queuer{this, signature, constraint->scope};
+    InstantiationQueuer queuer{constraint->scope, constraint->location, this, signature};
     queuer.traverse(target);
 
     instantiatedAliases[signature] = target;
@@ -730,6 +839,152 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
     return true;
 }
 
+bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<const Constraint> constraint)
+{
+    TypeId fn = follow(c.fn);
+    TypePackId result = follow(c.result);
+
+    if (isBlocked(c.fn))
+    {
+        return block(c.fn, constraint);
+    }
+
+    const FunctionTypeVar* ftv = get<FunctionTypeVar>(fn);
+    bool usedMagic = false;
+
+    if (ftv && ftv->dcrMagicFunction != nullptr)
+    {
+        usedMagic = ftv->dcrMagicFunction(NotNull(this), result, c.astFragment);
+    }
+
+    if (!usedMagic)
+    {
+        for (const auto& inner : c.innerConstraints)
+        {
+            unsolvedConstraints.push_back(inner);
+        }
+
+        asMutable(c.result)->ty.emplace<FreeTypePack>(constraint->scope);
+    }
+
+    unblock(c.result);
+
+    return true;
+}
+
+bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const IterableConstraint& c, NotNull<const Constraint> constraint, bool force)
+{
+    auto block_ = [&](auto&& t) {
+        if (force)
+        {
+            // TODO: I believe it is the case that, if we are asked to force
+            // this constraint, then we can do nothing but fail.  I'd like to
+            // find a code sample that gets here.
+            LUAU_ASSERT(0);
+        }
+        else
+            block(t, constraint);
+        return false;
+    };
+
+    // We may have to block here if we don't know what the iteratee type is,
+    // if it's a free table, if we don't know it has a metatable, and so on.
+    iteratorTy = follow(iteratorTy);
+    if (get<FreeTypeVar>(iteratorTy))
+        return block_(iteratorTy);
+
+    auto anyify = [&](auto ty) {
+        Anyification anyify{arena, constraint->scope, &iceReporter, getSingletonTypes().anyType, getSingletonTypes().anyTypePack};
+        std::optional anyified = anyify.substitute(ty);
+        if (!anyified)
+            reportError(CodeTooComplex{}, constraint->location);
+        else
+            unify(*anyified, ty, constraint->scope);
+    };
+
+    auto errorify = [&](auto ty) {
+        Anyification anyify{
+            arena, constraint->scope, &iceReporter, getSingletonTypes().errorRecoveryType(), getSingletonTypes().errorRecoveryTypePack()};
+        std::optional errorified = anyify.substitute(ty);
+        if (!errorified)
+            reportError(CodeTooComplex{}, constraint->location);
+        else
+            unify(*errorified, ty, constraint->scope);
+    };
+
+    if (get<AnyTypeVar>(iteratorTy))
+    {
+        anyify(c.variables);
+        return true;
+    }
+
+    if (get<ErrorTypeVar>(iteratorTy))
+    {
+        errorify(c.variables);
+        return true;
+    }
+
+    // Irksome: I don't think we have any way to guarantee that this table
+    // type never has a metatable.
+
+    if (auto iteratorTable = get<TableTypeVar>(iteratorTy))
+    {
+        if (iteratorTable->state == TableState::Free)
+            return block_(iteratorTy);
+
+        if (iteratorTable->indexer)
+        {
+            TypePackId expectedVariablePack = arena->addTypePack({iteratorTable->indexer->indexType, iteratorTable->indexer->indexResultType});
+            unify(c.variables, expectedVariablePack, constraint->scope);
+        }
+        else
+            errorify(c.variables);
+    }
+    else if (auto iteratorMetatable = get<MetatableTypeVar>(iteratorTy))
+    {
+        TypeId metaTy = follow(iteratorMetatable->metatable);
+        if (get<FreeTypeVar>(metaTy))
+            return block_(metaTy);
+
+        LUAU_ASSERT(0);
+    }
+    else
+        errorify(c.variables);
+
+    return true;
+}
+
+bool ConstraintSolver::tryDispatchIterableFunction(
+    TypeId nextTy, TypeId tableTy, TypeId firstIndexTy, const IterableConstraint& c, NotNull<const Constraint> constraint, bool force)
+{
+    // We need to know whether or not this type is nil or not.
+    // If we don't know, block and reschedule ourselves.
+    firstIndexTy = follow(firstIndexTy);
+    if (get<FreeTypeVar>(firstIndexTy))
+    {
+        if (force)
+            LUAU_ASSERT(0);
+        else
+            block(firstIndexTy, constraint);
+        return false;
+    }
+
+    const TypeId firstIndex = isNil(firstIndexTy) ? arena->freshType(constraint->scope) // FIXME: Surely this should be a union (free | nil)
+                                                  : firstIndexTy;
+
+    // nextTy : (tableTy, indexTy?) -> (indexTy, valueTailTy...)
+    const TypePackId nextArgPack = arena->addTypePack({tableTy, arena->addType(UnionTypeVar{{firstIndex, getSingletonTypes().nilType}})});
+    const TypePackId valueTailTy = arena->addTypePack(FreeTypePack{constraint->scope});
+    const TypePackId nextRetPack = arena->addTypePack(TypePack{{firstIndex}, valueTailTy});
+
+    const TypeId expectedNextTy = arena->addType(FunctionTypeVar{nextArgPack, nextRetPack});
+    unify(nextTy, expectedNextTy, constraint->scope);
+
+    pushConstraint(constraint->scope, constraint->location, PackSubtypeConstraint{c.variables, nextRetPack});
+
+    return true;
+}
+
 void ConstraintSolver::block_(BlockedConstraintId target, NotNull<const Constraint> constraint)
 {
     blocked[target].push_back(constraint);
@@ -741,14 +996,14 @@ void ConstraintSolver::block_(BlockedConstraintId target, NotNull<const Constrai
 void ConstraintSolver::block(NotNull<const Constraint> target, NotNull<const Constraint> constraint)
 {
     if (FFlag::DebugLuauLogSolver)
-        printf("block Constraint %s on\t%s\n", toString(*target).c_str(), toString(*constraint).c_str());
+        printf("block Constraint %s on\t%s\n", toString(*target, opts).c_str(), toString(*constraint, opts).c_str());
     block_(target, constraint);
 }
 
 bool ConstraintSolver::block(TypeId target, NotNull<const Constraint> constraint)
 {
     if (FFlag::DebugLuauLogSolver)
-        printf("block TypeId %s on\t%s\n", toString(target).c_str(), toString(*constraint).c_str());
+        printf("block TypeId %s on\t%s\n", toString(target, opts).c_str(), toString(*constraint, opts).c_str());
     block_(target, constraint);
     return false;
 }
@@ -756,7 +1011,7 @@ bool ConstraintSolver::block(TypeId target, NotNull<const Constraint> constraint
 bool ConstraintSolver::block(TypePackId target, NotNull<const Constraint> constraint)
 {
     if (FFlag::DebugLuauLogSolver)
-        printf("block TypeId %s on\t%s\n", toString(target).c_str(), toString(*constraint).c_str());
+        printf("block TypeId %s on\t%s\n", toString(target, opts).c_str(), toString(*constraint, opts).c_str());
     block_(target, constraint);
     return false;
 }
@@ -772,7 +1027,7 @@ void ConstraintSolver::unblock_(BlockedConstraintId progressed)
     {
         auto& count = blockedConstraints[unblockedConstraint];
         if (FFlag::DebugLuauLogSolver)
-            printf("Unblocking count=%d\t%s\n", int(count), toString(*unblockedConstraint).c_str());
+            printf("Unblocking count=%d\t%s\n", int(count), toString(*unblockedConstraint, opts).c_str());
 
         // This assertion being hit indicates that `blocked` and
         // `blockedConstraints` desynchronized at some point. This is problematic
@@ -817,6 +1072,11 @@ bool ConstraintSolver::isBlocked(TypeId ty)
     return nullptr != get<BlockedTypeVar>(follow(ty)) || nullptr != get<PendingExpansionTypeVar>(follow(ty));
 }
 
+bool ConstraintSolver::isBlocked(TypePackId tp)
+{
+    return nullptr != get<BlockedTypePack>(follow(tp));
+}
+
 bool ConstraintSolver::isBlocked(NotNull<const Constraint> constraint)
 {
     auto blockedIt = blockedConstraints.find(constraint);
@@ -830,6 +1090,13 @@ void ConstraintSolver::unify(TypeId subType, TypeId superType, NotNull<Scope> sc
 
     u.tryUnify(subType, superType);
 
+    if (!u.errors.empty())
+    {
+        TypeId errorType = getSingletonTypes().errorRecoveryType();
+        u.tryUnify(subType, errorType);
+        u.tryUnify(superType, errorType);
+    }
+
     const auto [changedTypes, changedPacks] = u.log.getChanges();
 
     u.log.commit();
@@ -853,22 +1120,69 @@ void ConstraintSolver::unify(TypePackId subPack, TypePackId superPack, NotNull<S
     unblock(changedPacks);
 }
 
-void ConstraintSolver::pushConstraint(ConstraintV cv, NotNull<Scope> scope)
+void ConstraintSolver::pushConstraint(NotNull<Scope> scope, const Location& location, ConstraintV cv)
 {
-    std::unique_ptr<Constraint> c = std::make_unique<Constraint>(std::move(cv), scope);
+    std::unique_ptr<Constraint> c = std::make_unique<Constraint>(scope, location, std::move(cv));
     NotNull<Constraint> borrow = NotNull(c.get());
     solverConstraints.push_back(std::move(c));
     unsolvedConstraints.push_back(borrow);
 }
 
+TypeId ConstraintSolver::resolveModule(const ModuleInfo& info, const Location& location)
+{
+    if (info.name.empty())
+    {
+        reportError(UnknownRequire{}, location);
+        return getSingletonTypes().errorRecoveryType();
+    }
+
+    std::string humanReadableName = moduleResolver->getHumanReadableModuleName(info.name);
+
+    for (const auto& [location, path] : requireCycles)
+    {
+        if (!path.empty() && path.front() == humanReadableName)
+            return getSingletonTypes().anyType;
+    }
+
+    ModulePtr module = moduleResolver->getModule(info.name);
+    if (!module)
+    {
+        if (!moduleResolver->moduleExists(info.name) && !info.optional)
+            reportError(UnknownRequire{humanReadableName}, location);
+
+        return getSingletonTypes().errorRecoveryType();
+    }
+
+    if (module->type != SourceCode::Type::Module)
+    {
+        reportError(IllegalRequire{humanReadableName, "Module is not a ModuleScript. It cannot be required."}, location);
+        return getSingletonTypes().errorRecoveryType();
+    }
+
+    TypePackId modulePack = module->getModuleScope()->returnType;
+    if (get<Unifiable::Error>(modulePack))
+        return getSingletonTypes().errorRecoveryType();
+
+    std::optional<TypeId> moduleType = first(modulePack);
+    if (!moduleType)
+    {
+        reportError(IllegalRequire{humanReadableName, "Module does not return exactly 1 value. It cannot be required."}, location);
+        return getSingletonTypes().errorRecoveryType();
+    }
+
+    return *moduleType;
+}
+
 void ConstraintSolver::reportError(TypeErrorData&& data, const Location& location)
 {
     errors.emplace_back(location, std::move(data));
+    errors.back().moduleName = currentModuleName;
 }
 
 void ConstraintSolver::reportError(TypeError e)
 {
     errors.emplace_back(std::move(e));
+    errors.back().moduleName = currentModuleName;
 }
 
 } // namespace Luau
diff --git a/Analysis/src/ConstraintSolverLogger.cpp b/Analysis/src/ConstraintSolverLogger.cpp
index 097ceeec..5ba40521 100644
--- a/Analysis/src/ConstraintSolverLogger.cpp
+++ b/Analysis/src/ConstraintSolverLogger.cpp
@@ -3,6 +3,7 @@
 #include "Luau/ConstraintSolverLogger.h"
 
 #include "Luau/JsonEmitter.h"
+#include "Luau/ToString.h"
 
 LUAU_FASTFLAG(LuauFixNameMaps);
 
diff --git a/Analysis/src/Frontend.cpp b/Analysis/src/Frontend.cpp
index c8c5d4b5..d8839f2f 100644
--- a/Analysis/src/Frontend.cpp
+++ b/Analysis/src/Frontend.cpp
@@ -14,6 +14,7 @@
 #include "Luau/TypeChecker2.h"
 #include "Luau/TypeInfer.h"
 #include "Luau/Variant.h"
+#include "Luau/BuiltinDefinitions.h"
 
 #include <algorithm>
 #include <chrono>
@@ -99,7 +100,7 @@ LoadDefinitionFileResult Frontend::loadDefinitionFile(std::string_view source, c
     module.root = parseResult.root;
     module.mode = Mode::Definition;
 
-    ModulePtr checkedModule = check(module, Mode::Definition, globalScope);
+    ModulePtr checkedModule = check(module, Mode::Definition, globalScope, {});
 
     if (checkedModule->errors.size() > 0)
         return LoadDefinitionFileResult{false, parseResult, checkedModule};
@@ -526,7 +527,7 @@ CheckResult Frontend::check(const ModuleName& name, std::optional<FrontendOption
 
         typeChecker.requireCycles = requireCycles;
 
-        ModulePtr module = FFlag::DebugLuauDeferredConstraintResolution ? check(sourceModule, mode, environmentScope)
+        ModulePtr module = FFlag::DebugLuauDeferredConstraintResolution ? check(sourceModule, mode, environmentScope, requireCycles)
                                                                         : typeChecker.check(sourceModule, mode, environmentScope);
 
         stats.timeCheck += getTimestamp() - timestamp;
@@ -832,15 +833,15 @@ ScopePtr Frontend::getGlobalScope()
     return globalScope;
 }
 
-ModulePtr Frontend::check(const SourceModule& sourceModule, Mode mode, const ScopePtr& environmentScope)
+ModulePtr Frontend::check(const SourceModule& sourceModule, Mode mode, const ScopePtr& environmentScope, std::vector<RequireCycle> requireCycles)
 {
     ModulePtr result = std::make_shared<Module>();
 
-    ConstraintGraphBuilder cgb{sourceModule.name, result, &result->internalTypes, NotNull(&iceHandler), getGlobalScope()};
+    ConstraintGraphBuilder cgb{sourceModule.name, result, &result->internalTypes, NotNull(&moduleResolver), NotNull(&iceHandler), getGlobalScope()};
     cgb.visit(sourceModule.root);
     result->errors = std::move(cgb.errors);
 
-    ConstraintSolver cs{&result->internalTypes, NotNull(cgb.rootScope)};
+    ConstraintSolver cs{&result->internalTypes, NotNull(cgb.rootScope), sourceModule.name, NotNull(&moduleResolver), requireCycles};
     cs.run();
 
     for (TypeError& e : cs.errors)
@@ -852,11 +853,12 @@ ModulePtr Frontend::check(const SourceModule& sourceModule, Mode mode, const Sco
     result->astOriginalCallTypes = std::move(cgb.astOriginalCallTypes);
     result->astResolvedTypes = std::move(cgb.astResolvedTypes);
     result->astResolvedTypePacks = std::move(cgb.astResolvedTypePacks);
-
-    result->clonePublicInterface(iceHandler);
+    result->type = sourceModule.type;
 
     Luau::check(sourceModule, result.get());
 
+    result->clonePublicInterface(iceHandler);
+
     return result;
 }
 
diff --git a/Analysis/src/Instantiation.cpp b/Analysis/src/Instantiation.cpp
index e98ab185..2d1d62f3 100644
--- a/Analysis/src/Instantiation.cpp
+++ b/Analysis/src/Instantiation.cpp
@@ -46,6 +46,7 @@ TypeId Instantiation::clean(TypeId ty)
 
     FunctionTypeVar clone = FunctionTypeVar{level, ftv->argTypes, ftv->retTypes, ftv->definition, ftv->hasSelf};
     clone.magicFunction = ftv->magicFunction;
+    clone.dcrMagicFunction = ftv->dcrMagicFunction;
     clone.tags = ftv->tags;
     clone.argNames = ftv->argNames;
     TypeId result = addType(std::move(clone));
diff --git a/Analysis/src/JsonEmitter.cpp b/Analysis/src/JsonEmitter.cpp
index e99619ba..9c8a7af9 100644
--- a/Analysis/src/JsonEmitter.cpp
+++ b/Analysis/src/JsonEmitter.cpp
@@ -11,7 +11,8 @@ namespace Luau::Json
 static constexpr int CHUNK_SIZE = 1024;
 
 ObjectEmitter::ObjectEmitter(NotNull<JsonEmitter> emitter)
-    : emitter(emitter), finished(false)
+    : emitter(emitter)
+    , finished(false)
 {
     comma = emitter->pushComma();
     emitter->writeRaw('{');
@@ -33,7 +34,8 @@ void ObjectEmitter::finish()
 }
 
 ArrayEmitter::ArrayEmitter(NotNull<JsonEmitter> emitter)
-    : emitter(emitter), finished(false)
+    : emitter(emitter)
+    , finished(false)
 {
     comma = emitter->pushComma();
     emitter->writeRaw('[');
diff --git a/Analysis/src/Linter.cpp b/Analysis/src/Linter.cpp
index 426ff9d6..669739a0 100644
--- a/Analysis/src/Linter.cpp
+++ b/Analysis/src/Linter.cpp
@@ -216,7 +216,8 @@ static bool similar(AstExpr* lhs, AstExpr* rhs)
             return false;
 
         for (size_t i = 0; i < le->strings.size; ++i)
-            if (le->strings.data[i].size != re->strings.data[i].size || memcmp(le->strings.data[i].data, re->strings.data[i].data, le->strings.data[i].size) != 0)
+            if (le->strings.data[i].size != re->strings.data[i].size ||
+                memcmp(le->strings.data[i].data, re->strings.data[i].data, le->strings.data[i].size) != 0)
                 return false;
 
         for (size_t i = 0; i < le->expressions.size; ++i)
@@ -2675,13 +2676,18 @@ public:
 private:
     LintContext* context;
 
-    bool isComparison(AstExprBinary::Op op)
+    static bool isEquality(AstExprBinary::Op op)
+    {
+        return op == AstExprBinary::CompareNe || op == AstExprBinary::CompareEq;
+    }
+
+    static bool isComparison(AstExprBinary::Op op)
     {
         return op == AstExprBinary::CompareNe || op == AstExprBinary::CompareEq || op == AstExprBinary::CompareLt || op == AstExprBinary::CompareLe ||
                op == AstExprBinary::CompareGt || op == AstExprBinary::CompareGe;
     }
 
-    bool isNot(AstExpr* node)
+    static bool isNot(AstExpr* node)
     {
         AstExprUnary* expr = node->as<AstExprUnary>();
 
@@ -2698,22 +2704,26 @@ private:
         {
             std::string op = toString(node->op);
 
-            if (node->op == AstExprBinary::CompareEq || node->op == AstExprBinary::CompareNe)
+            if (isEquality(node->op))
                 emitWarning(*context, LintWarning::Code_ComparisonPrecedence, node->location,
-                    "not X %s Y is equivalent to (not X) %s Y; consider using X %s Y, or wrap one of the expressions in parentheses to silence",
-                    op.c_str(), op.c_str(), node->op == AstExprBinary::CompareEq ? "~=" : "==");
+                    "not X %s Y is equivalent to (not X) %s Y; consider using X %s Y, or add parentheses to silence", op.c_str(), op.c_str(),
+                    node->op == AstExprBinary::CompareEq ? "~=" : "==");
             else
                 emitWarning(*context, LintWarning::Code_ComparisonPrecedence, node->location,
-                    "not X %s Y is equivalent to (not X) %s Y; wrap one of the expressions in parentheses to silence", op.c_str(), op.c_str());
+                    "not X %s Y is equivalent to (not X) %s Y; add parentheses to silence", op.c_str(), op.c_str());
         }
         else if (AstExprBinary* left = node->left->as<AstExprBinary>(); left && isComparison(left->op))
         {
             std::string lop = toString(left->op);
             std::string rop = toString(node->op);
 
-            emitWarning(*context, LintWarning::Code_ComparisonPrecedence, node->location,
-                "X %s Y %s Z is equivalent to (X %s Y) %s Z; wrap one of the expressions in parentheses to silence", lop.c_str(), rop.c_str(),
-                lop.c_str(), rop.c_str());
+            if (isEquality(left->op) || isEquality(node->op))
+                emitWarning(*context, LintWarning::Code_ComparisonPrecedence, node->location,
+                    "X %s Y %s Z is equivalent to (X %s Y) %s Z; add parentheses to silence", lop.c_str(), rop.c_str(), lop.c_str(), rop.c_str());
+            else
+                emitWarning(*context, LintWarning::Code_ComparisonPrecedence, node->location,
+                    "X %s Y %s Z is equivalent to (X %s Y) %s Z; did you mean X %s Y and Y %s Z?", lop.c_str(), rop.c_str(), lop.c_str(), rop.c_str(),
+                    lop.c_str(), rop.c_str());
         }
 
         return true;
diff --git a/Analysis/src/Module.cpp b/Analysis/src/Module.cpp
index de796c7a..4c9e9537 100644
--- a/Analysis/src/Module.cpp
+++ b/Analysis/src/Module.cpp
@@ -219,8 +219,7 @@ void Module::clonePublicInterface(InternalErrorReporter& ice)
 
     TypePackId returnType = moduleScope->returnType;
     std::optional<TypePackId> varargPack = FFlag::DebugLuauDeferredConstraintResolution ? std::nullopt : moduleScope->varargPack;
-    std::unordered_map<Name, TypeFun>* exportedTypeBindings =
-        FFlag::DebugLuauDeferredConstraintResolution ? nullptr : &moduleScope->exportedTypeBindings;
+    std::unordered_map<Name, TypeFun>* exportedTypeBindings = &moduleScope->exportedTypeBindings;
 
     TxnLog log;
     ClonePublicInterface clonePublicInterface{&log, this};
diff --git a/Analysis/src/Substitution.cpp b/Analysis/src/Substitution.cpp
index 0beeb58c..fa12f306 100644
--- a/Analysis/src/Substitution.cpp
+++ b/Analysis/src/Substitution.cpp
@@ -510,7 +510,7 @@ void Substitution::foundDirty(TypeId ty)
     ty = log->follow(ty);
 
     if (FFlag::LuauSubstitutionReentrant && newTypes.contains(ty))
-            return;
+        return;
 
     if (isDirty(ty))
         newTypes[ty] = follow(clean(ty));
@@ -523,7 +523,7 @@ void Substitution::foundDirty(TypePackId tp)
     tp = log->follow(tp);
 
     if (FFlag::LuauSubstitutionReentrant && newPacks.contains(tp))
-            return;
+        return;
 
     if (isDirty(tp))
         newPacks[tp] = follow(clean(tp));
diff --git a/Analysis/src/ToString.cpp b/Analysis/src/ToString.cpp
index ace44cda..13cd7490 100644
--- a/Analysis/src/ToString.cpp
+++ b/Analysis/src/ToString.cpp
@@ -1034,6 +1034,13 @@ struct TypePackStringifier
     {
         stringify(btv.boundTo);
     }
+
+    void operator()(TypePackId, const BlockedTypePack& btp)
+    {
+        state.emit("*blocked-tp-");
+        state.emit(btp.index);
+        state.emit("*");
+    }
 };
 
 void TypeVarStringifier::stringify(TypePackId tp)
@@ -1095,9 +1102,8 @@ ToStringResult toStringDetailed(TypeId ty, ToStringOptions& opts)
 
     ToStringResult result;
 
-    StringifierState state = FFlag::LuauFixNameMaps
-        ? StringifierState{opts, result, opts.nameMap}
-        : StringifierState{opts, result, opts.DEPRECATED_nameMap};
+    StringifierState state =
+        FFlag::LuauFixNameMaps ? StringifierState{opts, result, opts.nameMap} : StringifierState{opts, result, opts.DEPRECATED_nameMap};
 
     std::set<TypeId> cycles;
     std::set<TypePackId> cycleTPs;
@@ -1204,9 +1210,8 @@ ToStringResult toStringDetailed(TypePackId tp, ToStringOptions& opts)
      * 4. Print out the root of the type using the same algorithm as step 3.
      */
     ToStringResult result;
-    StringifierState state = FFlag::LuauFixNameMaps
-        ? StringifierState{opts, result, opts.nameMap}
-        : StringifierState{opts, result, opts.DEPRECATED_nameMap};
+    StringifierState state =
+        FFlag::LuauFixNameMaps ? StringifierState{opts, result, opts.nameMap} : StringifierState{opts, result, opts.DEPRECATED_nameMap};
 
     std::set<TypeId> cycles;
     std::set<TypePackId> cycleTPs;
@@ -1292,9 +1297,8 @@ std::string toString(const TypePackVar& tp, ToStringOptions& opts)
 std::string toStringNamedFunction(const std::string& funcName, const FunctionTypeVar& ftv, ToStringOptions& opts)
 {
     ToStringResult result;
-    StringifierState state = FFlag::LuauFixNameMaps
-        ? StringifierState{opts, result, opts.nameMap}
-        : StringifierState{opts, result, opts.DEPRECATED_nameMap};
+    StringifierState state =
+        FFlag::LuauFixNameMaps ? StringifierState{opts, result, opts.nameMap} : StringifierState{opts, result, opts.DEPRECATED_nameMap};
     TypeVarStringifier tvs{state};
 
     state.emit(funcName);
@@ -1427,8 +1431,7 @@ std::string toString(const Constraint& constraint, ToStringOptions& opts)
         using T = std::decay_t<decltype(c)>;
 
         // TODO: Inline and delete this function when clipping FFlag::LuauFixNameMaps
-        auto tos = [](auto&& a, ToStringOptions& opts)
-        {
+        auto tos = [](auto&& a, ToStringOptions& opts) {
             if (FFlag::LuauFixNameMaps)
                 return toString(a, opts);
             else
@@ -1478,6 +1481,13 @@ std::string toString(const Constraint& constraint, ToStringOptions& opts)
 
             return resultStr + " ~ Binary<" + toString(c.op) + ", " + leftStr + ", " + rightStr + ">";
         }
+        else if constexpr (std::is_same_v<T, IterableConstraint>)
+        {
+            std::string iteratorStr = tos(c.iterator, opts);
+            std::string variableStr = tos(c.variables, opts);
+
+            return variableStr + " ~ Iterate<" + iteratorStr + ">";
+        }
         else if constexpr (std::is_same_v<T, NameConstraint>)
         {
             std::string namedStr = tos(c.namedType, opts);
@@ -1488,6 +1498,10 @@ std::string toString(const Constraint& constraint, ToStringOptions& opts)
             std::string targetStr = tos(c.target, opts);
             return "expand " + targetStr;
         }
+        else if constexpr (std::is_same_v<T, FunctionCallConstraint>)
+        {
+            return "call " + tos(c.fn, opts) + " with { result = " + tos(c.result, opts) + " }";
+        }
         else
             static_assert(always_false_v<T>, "Non-exhaustive constraint switch");
     };
diff --git a/Analysis/src/TypeArena.cpp b/Analysis/src/TypeArena.cpp
index 0c89d130..c7980ab0 100644
--- a/Analysis/src/TypeArena.cpp
+++ b/Analysis/src/TypeArena.cpp
@@ -31,6 +31,15 @@ TypeId TypeArena::freshType(TypeLevel level)
     return allocated;
 }
 
+TypeId TypeArena::freshType(Scope* scope)
+{
+    TypeId allocated = typeVars.allocate(FreeTypeVar{scope});
+
+    asMutable(allocated)->owningArena = this;
+
+    return allocated;
+}
+
 TypePackId TypeArena::addTypePack(std::initializer_list<TypeId> types)
 {
     TypePackId allocated = typePacks.allocate(TypePack{std::move(types)});
@@ -40,9 +49,9 @@ TypePackId TypeArena::addTypePack(std::initializer_list<TypeId> types)
     return allocated;
 }
 
-TypePackId TypeArena::addTypePack(std::vector<TypeId> types)
+TypePackId TypeArena::addTypePack(std::vector<TypeId> types, std::optional<TypePackId> tail)
 {
-    TypePackId allocated = typePacks.allocate(TypePack{std::move(types)});
+    TypePackId allocated = typePacks.allocate(TypePack{std::move(types), tail});
 
     asMutable(allocated)->owningArena = this;
 
diff --git a/Analysis/src/TypeAttach.cpp b/Analysis/src/TypeAttach.cpp
index f21a4fa9..84494083 100644
--- a/Analysis/src/TypeAttach.cpp
+++ b/Analysis/src/TypeAttach.cpp
@@ -373,6 +373,11 @@ public:
         return Luau::visit(*this, btp.boundTo->ty);
     }
 
+    AstTypePack* operator()(const BlockedTypePack& btp) const
+    {
+        return allocator->alloc<AstTypePackGeneric>(Location(), AstName("*blocked*"));
+    }
+
     AstTypePack* operator()(const TypePack& tp) const
     {
         AstArray<AstType*> head;
diff --git a/Analysis/src/TypeChecker2.cpp b/Analysis/src/TypeChecker2.cpp
index e5813cd2..480bdf40 100644
--- a/Analysis/src/TypeChecker2.cpp
+++ b/Analysis/src/TypeChecker2.cpp
@@ -166,7 +166,8 @@ struct TypeChecker2
         auto pusher = pushStack(stat);
 
         if (0)
-        {}
+        {
+        }
         else if (auto s = stat->as<AstStatBlock>())
             return visit(s);
         else if (auto s = stat->as<AstStatIf>())
@@ -239,11 +240,9 @@ struct TypeChecker2
         visit(repeatStatement->condition);
     }
 
-    void visit(AstStatBreak*)
-    {}
+    void visit(AstStatBreak*) {}
 
-    void visit(AstStatContinue*)
-    {}
+    void visit(AstStatContinue*) {}
 
     void visit(AstStatReturn* ret)
     {
@@ -339,6 +338,50 @@ struct TypeChecker2
         visit(forStatement->body);
     }
 
+    // "Render" a type pack out to an array of a given length.  Expands
+    // variadics and various other things to get there.
+    static std::vector<TypeId> flatten(TypeArena& arena, TypePackId pack, size_t length)
+    {
+        std::vector<TypeId> result;
+
+        auto it = begin(pack);
+        auto endIt = end(pack);
+
+        while (it != endIt)
+        {
+            result.push_back(*it);
+
+            if (result.size() >= length)
+                return result;
+
+            ++it;
+        }
+
+        if (!it.tail())
+            return result;
+
+        TypePackId tail = *it.tail();
+        if (get<TypePack>(tail))
+            LUAU_ASSERT(0);
+        else if (auto vtp = get<VariadicTypePack>(tail))
+        {
+            while (result.size() < length)
+                result.push_back(vtp->ty);
+        }
+        else if (get<FreeTypePack>(tail) || get<GenericTypePack>(tail))
+        {
+            while (result.size() < length)
+                result.push_back(arena.addType(FreeTypeVar{nullptr}));
+        }
+        else if (auto etp = get<Unifiable::Error>(tail))
+        {
+            while (result.size() < length)
+                result.push_back(getSingletonTypes().errorRecoveryType());
+        }
+
+        return result;
+    }
+
     void visit(AstStatForIn* forInStatement)
     {
         for (AstLocal* local : forInStatement->vars)
@@ -351,6 +394,128 @@ struct TypeChecker2
             visit(expr);
 
         visit(forInStatement->body);
+
+        // Rule out crazy stuff.  Maybe possible if the file is not syntactically valid.
+        if (!forInStatement->vars.size || !forInStatement->values.size)
+            return;
+
+        NotNull<Scope> scope = stack.back();
+        TypeArena tempArena;
+
+        std::vector<TypeId> variableTypes;
+        for (AstLocal* var : forInStatement->vars)
+        {
+            std::optional<TypeId> ty = scope->lookup(var);
+            LUAU_ASSERT(ty);
+            variableTypes.emplace_back(*ty);
+        }
+
+        // ugh.  There's nothing in the AST to hang a whole type pack on for the
+        // set of iteratees, so we have to piece it back together by hand.
+        std::vector<TypeId> valueTypes;
+        for (size_t i = 0; i < forInStatement->values.size - 1; ++i)
+            valueTypes.emplace_back(lookupType(forInStatement->values.data[i]));
+        TypePackId iteratorTail = lookupPack(forInStatement->values.data[forInStatement->values.size - 1]);
+        TypePackId iteratorPack = tempArena.addTypePack(valueTypes, iteratorTail);
+
+        // ... and then expand it out to 3 values (if possible)
+        const std::vector<TypeId> iteratorTypes = flatten(tempArena, iteratorPack, 3);
+        if (iteratorTypes.empty())
+        {
+            reportError(GenericError{"for..in loops require at least one value to iterate over.  Got zero"}, getLocation(forInStatement->values));
+            return;
+        }
+        TypeId iteratorTy = follow(iteratorTypes[0]);
+
+        /*
+         * If the first iterator argument is a function
+         *  * There must be 1 to 3 iterator arguments.  Name them (nextTy,
+         *    arrayTy, startIndexTy)
+         *  * The return type of nextTy() must correspond to the variables'
+         *    types and counts.  HOWEVER the first iterator will never be nil.
+         *  * The first return value of nextTy must be compatible with
+         *    startIndexTy.
+         *  * The first argument to nextTy() must be compatible with arrayTy if
+         *    present.  nil if not.
+         *  * The second argument to nextTy() must be compatible with
+         *    startIndexTy if it is present.  Else, it must be compatible with
+         *    nil.
+         *  * nextTy() must be callable with only 2 arguments.
+         */
+        if (const FunctionTypeVar* nextFn = get<FunctionTypeVar>(iteratorTy))
+        {
+            if (iteratorTypes.size() < 1 || iteratorTypes.size() > 3)
+                reportError(GenericError{"for..in loops must be passed (next, [table[, state]])"}, getLocation(forInStatement->values));
+
+            // It is okay if there aren't enough iterators, but the iteratee must provide enough.
+            std::vector<TypeId> expectedVariableTypes = flatten(tempArena, nextFn->retTypes, variableTypes.size());
+            if (expectedVariableTypes.size() < variableTypes.size())
+                reportError(GenericError{"next() does not return enough values"}, forInStatement->vars.data[0]->location);
+
+            for (size_t i = 0; i < std::min(expectedVariableTypes.size(), variableTypes.size()); ++i)
+                reportErrors(tryUnify(scope, forInStatement->vars.data[i]->location, variableTypes[i], expectedVariableTypes[i]));
+
+            // nextFn is going to be invoked with (arrayTy, startIndexTy)
+
+            // It will be passed two arguments on every iteration save the
+            // first.
+
+            // It may be invoked with 0 or 1 argument on the first iteration.
+            // This depends on the types in iterateePack and therefore
+            // iteratorTypes.
+
+            // If iteratorTypes is too short to be a valid call to nextFn, we have to report a count mismatch error.
+            // If 2 is too short to be a valid call to nextFn, we have to report a count mismatch error.
+            // If 2 is too long to be a valid call to nextFn, we have to report a count mismatch error.
+            auto [minCount, maxCount] = getParameterExtents(TxnLog::empty(), nextFn->argTypes);
+
+            if (minCount > 2)
+                reportError(CountMismatch{2, minCount, CountMismatch::Arg}, forInStatement->vars.data[0]->location);
+            if (maxCount && *maxCount < 2)
+                reportError(CountMismatch{2, *maxCount, CountMismatch::Arg}, forInStatement->vars.data[0]->location);
+
+            const std::vector<TypeId> flattenedArgTypes = flatten(tempArena, nextFn->argTypes, 2);
+            const auto [argTypes, argsTail] = Luau::flatten(nextFn->argTypes);
+
+            size_t firstIterationArgCount = iteratorTypes.empty() ? 0 : iteratorTypes.size() - 1;
+            size_t actualArgCount = expectedVariableTypes.size();
+
+            if (firstIterationArgCount < minCount)
+                reportError(CountMismatch{2, firstIterationArgCount, CountMismatch::Arg}, forInStatement->vars.data[0]->location);
+            else if (actualArgCount < minCount)
+                reportError(CountMismatch{2, actualArgCount, CountMismatch::Arg}, forInStatement->vars.data[0]->location);
+
+            if (iteratorTypes.size() >= 2 && flattenedArgTypes.size() > 0)
+            {
+                size_t valueIndex = forInStatement->values.size > 1 ? 1 : 0;
+                reportErrors(tryUnify(scope, forInStatement->values.data[valueIndex]->location, iteratorTypes[1], flattenedArgTypes[0]));
+            }
+
+            if (iteratorTypes.size() == 3 && flattenedArgTypes.size() > 1)
+            {
+                size_t valueIndex = forInStatement->values.size > 2 ? 2 : 0;
+                reportErrors(tryUnify(scope, forInStatement->values.data[valueIndex]->location, iteratorTypes[2], flattenedArgTypes[1]));
+            }
+        }
+        else if (const TableTypeVar* ttv = get<TableTypeVar>(iteratorTy))
+        {
+            if ((forInStatement->vars.size == 1 || forInStatement->vars.size == 2) && ttv->indexer)
+            {
+                reportErrors(tryUnify(scope, forInStatement->vars.data[0]->location, variableTypes[0], ttv->indexer->indexType));
+                if (variableTypes.size() == 2)
+                    reportErrors(tryUnify(scope, forInStatement->vars.data[1]->location, variableTypes[1], ttv->indexer->indexResultType));
+            }
+            else
+                reportError(GenericError{"Cannot iterate over a table without indexer"}, forInStatement->values.data[0]->location);
+        }
+        else if (get<AnyTypeVar>(iteratorTy) || get<ErrorTypeVar>(iteratorTy))
+        {
+            // nothing
+        }
+        else
+        {
+            reportError(CannotCallNonFunction{iteratorTy}, forInStatement->values.data[0]->location);
+        }
     }
 
     void visit(AstStatAssign* assign)
@@ -456,7 +621,8 @@ struct TypeChecker2
         auto StackPusher = pushStack(expr);
 
         if (0)
-        {}
+        {
+        }
         else if (auto e = expr->as<AstExprGroup>())
             return visit(e);
         else if (auto e = expr->as<AstExprConstantNil>())
@@ -561,9 +727,21 @@ struct TypeChecker2
 
         TypePackId expectedRetType = lookupPack(call);
         TypeId functionType = lookupType(call->func);
-        TypeId instantiatedFunctionType = instantiation.substitute(functionType).value_or(nullptr);
         LUAU_ASSERT(functionType);
 
+        if (get<AnyTypeVar>(functionType) || get<ErrorTypeVar>(functionType))
+            return;
+
+        // TODO: Lots of other types are callable: intersections of functions
+        // and things with the __call metamethod.
+        if (!get<FunctionTypeVar>(functionType))
+        {
+            reportError(CannotCallNonFunction{functionType}, call->func->location);
+            return;
+        }
+
+        TypeId instantiatedFunctionType = follow(instantiation.substitute(functionType).value_or(nullptr));
+
         TypePack args;
         for (AstExpr* arg : call->args)
         {
@@ -575,12 +753,11 @@ struct TypeChecker2
         TypePackId argsTp = arena.addTypePack(args);
         FunctionTypeVar ftv{argsTp, expectedRetType};
         TypeId expectedType = arena.addType(ftv);
+
         if (!isSubtype(expectedType, instantiatedFunctionType, stack.back(), ice))
         {
-            unfreeze(module->interfaceTypes);
             CloneState cloneState;
-            expectedType = clone(expectedType, module->interfaceTypes, cloneState);
-            freeze(module->interfaceTypes);
+            expectedType = clone(expectedType, module->internalTypes, cloneState);
             reportError(TypeMismatch{expectedType, functionType}, call->location);
         }
     }
@@ -592,7 +769,8 @@ struct TypeChecker2
 
         // leftType must have a property called indexName->index
 
-        std::optional<TypeId> ty = getIndexTypeFromType(module->getModuleScope(), leftType, indexName->index.value, indexName->location, /* addErrors */ true);
+        std::optional<TypeId> ty =
+            getIndexTypeFromType(module->getModuleScope(), leftType, indexName->index.value, indexName->location, /* addErrors */ true);
         if (ty)
         {
             if (!isSubtype(resultType, *ty, stack.back(), ice))
@@ -972,18 +1150,34 @@ struct TypeChecker2
         }
     }
 
-    void reportError(TypeErrorData&& data, const Location& location)
+    template<typename TID>
+    ErrorVec tryUnify(NotNull<Scope> scope, const Location& location, TID subTy, TID superTy)
+    {
+        UnifierSharedState sharedState{&ice};
+        Unifier u{&module->internalTypes, Mode::Strict, scope, location, Covariant, sharedState};
+        u.anyIsTop = true;
+        u.tryUnify(subTy, superTy);
+
+        return std::move(u.errors);
+    }
+
+    void reportError(TypeErrorData data, const Location& location)
     {
         module->errors.emplace_back(location, sourceModule->name, std::move(data));
     }
 
     void reportError(TypeError e)
     {
-        module->errors.emplace_back(std::move(e));
+        reportError(std::move(e.data), e.location);
     }
 
-    std::optional<TypeId> getIndexTypeFromType(
-        const ScopePtr& scope, TypeId type, const std::string& prop, const Location& location, bool addErrors)
+    void reportErrors(ErrorVec errors)
+    {
+        for (TypeError e : errors)
+            reportError(std::move(e));
+    }
+
+    std::optional<TypeId> getIndexTypeFromType(const ScopePtr& scope, TypeId type, const std::string& prop, const Location& location, bool addErrors)
     {
         return Luau::getIndexTypeFromType(scope, module->errors, &module->internalTypes, type, prop, location, addErrors, ice);
     }
diff --git a/Analysis/src/TypeInfer.cpp b/Analysis/src/TypeInfer.cpp
index 77168053..2bda2804 100644
--- a/Analysis/src/TypeInfer.cpp
+++ b/Analysis/src/TypeInfer.cpp
@@ -32,7 +32,6 @@ LUAU_FASTINTVARIABLE(LuauCheckRecursionLimit, 300)
 LUAU_FASTINTVARIABLE(LuauVisitRecursionLimit, 500)
 LUAU_FASTFLAG(LuauKnowsTheDataModel3)
 LUAU_FASTFLAG(LuauAutocompleteDynamicLimits)
-LUAU_FASTFLAGVARIABLE(LuauExpectedTableUnionIndexerType, false)
 LUAU_FASTFLAGVARIABLE(LuauInplaceDemoteSkipAllBound, false)
 LUAU_FASTFLAGVARIABLE(LuauLowerBoundsCalculation, false)
 LUAU_FASTFLAGVARIABLE(DebugLuauFreezeDuringUnification, false)
@@ -45,6 +44,7 @@ LUAU_FASTFLAGVARIABLE(LuauBinaryNeedsExpectedTypesToo, false)
 LUAU_FASTFLAGVARIABLE(LuauNeverTypesAndOperatorsInference, false)
 LUAU_FASTFLAGVARIABLE(LuauReturnsFromCallsitesAreNotWidened, false)
 LUAU_FASTFLAGVARIABLE(LuauCompleteVisitor, false)
+LUAU_FASTFLAGVARIABLE(LuauUnionOfTypesFollow, false)
 
 namespace Luau
 {
@@ -1659,6 +1659,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& declar
         TypeId propTy = resolveType(scope, *prop.ty);
 
         bool assignToMetatable = isMetamethod(propName);
+        Luau::ClassTypeVar::Props& assignTo = assignToMetatable ? metatable->props : ctv->props;
 
         // Function types always take 'self', but this isn't reflected in the
         // parsed annotation. Add it here.
@@ -1674,16 +1675,13 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& declar
             }
         }
 
-        if (ctv->props.count(propName) == 0)
+        if (assignTo.count(propName) == 0)
         {
-            if (assignToMetatable)
-                metatable->props[propName] = {propTy};
-            else
-                ctv->props[propName] = {propTy};
+            assignTo[propName] = {propTy};
         }
         else
         {
-            TypeId currentTy = assignToMetatable ? metatable->props[propName].type : ctv->props[propName].type;
+            TypeId currentTy = assignTo[propName].type;
 
             // We special-case this logic to keep the intersection flat; otherwise we
             // would create a ton of nested intersection types.
@@ -1693,19 +1691,13 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& declar
                 options.push_back(propTy);
                 TypeId newItv = addType(IntersectionTypeVar{std::move(options)});
 
-                if (assignToMetatable)
-                    metatable->props[propName] = {newItv};
-                else
-                    ctv->props[propName] = {newItv};
+                assignTo[propName] = {newItv};
             }
             else if (get<FunctionTypeVar>(currentTy))
             {
                 TypeId intersection = addType(IntersectionTypeVar{{currentTy, propTy}});
 
-                if (assignToMetatable)
-                    metatable->props[propName] = {intersection};
-                else
-                    ctv->props[propName] = {intersection};
+                assignTo[propName] = {intersection};
             }
             else
             {
@@ -2351,7 +2343,7 @@ WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExp
                         {
                             if (auto prop = ttv->props.find(key->value.data); prop != ttv->props.end())
                                 expectedResultTypes.push_back(prop->second.type);
-                            else if (FFlag::LuauExpectedTableUnionIndexerType && ttv->indexer && maybeString(ttv->indexer->indexType))
+                            else if (ttv->indexer && maybeString(ttv->indexer->indexType))
                                 expectedResultTypes.push_back(ttv->indexer->indexResultType);
                         }
                     }
@@ -2506,6 +2498,12 @@ std::string opToMetaTableEntry(const AstExprBinary::Op& op)
 
 TypeId TypeChecker::unionOfTypes(TypeId a, TypeId b, const ScopePtr& scope, const Location& location, bool unifyFreeTypes)
 {
+    if (FFlag::LuauUnionOfTypesFollow)
+    {
+        a = follow(a);
+        b = follow(b);
+    }
+
     if (unifyFreeTypes && (get<FreeTypeVar>(a) || get<FreeTypeVar>(b)))
     {
         if (unify(b, a, scope, location))
@@ -3667,33 +3665,6 @@ WithPredicate<TypePackId> TypeChecker::checkExprPackHelper(const ScopePtr& scope
     }
 }
 
-// Returns the minimum number of arguments the argument list can accept.
-static size_t getMinParameterCount(TxnLog* log, TypePackId tp)
-{
-    size_t minCount = 0;
-    size_t optionalCount = 0;
-
-    auto it = begin(tp, log);
-    auto endIter = end(tp);
-
-    while (it != endIter)
-    {
-        TypeId ty = *it;
-        if (isOptional(ty))
-            ++optionalCount;
-        else
-        {
-            minCount += optionalCount;
-            optionalCount = 0;
-            minCount++;
-        }
-
-        ++it;
-    }
-
-    return minCount;
-}
-
 void TypeChecker::checkArgumentList(
     const ScopePtr& scope, Unifier& state, TypePackId argPack, TypePackId paramPack, const std::vector<Location>& argLocations)
 {
@@ -3713,7 +3684,7 @@ void TypeChecker::checkArgumentList(
         if (!argLocations.empty())
             location = {state.location.begin, argLocations.back().end};
 
-        size_t minParams = getMinParameterCount(&state.log, paramPack);
+        size_t minParams = getParameterExtents(&state.log, paramPack).first;
         state.reportError(TypeError{location, CountMismatch{minParams, std::distance(begin(argPack), end(argPack))}});
     };
 
@@ -3812,7 +3783,7 @@ void TypeChecker::checkArgumentList(
                 } // ok
                 else
                 {
-                    size_t minParams = getMinParameterCount(&state.log, paramPack);
+                    size_t minParams = getParameterExtents(&state.log, paramPack).first;
 
                     std::optional<TypePackId> tail = flatten(paramPack, state.log).second;
                     bool isVariadic = tail && Luau::isVariadic(*tail);
diff --git a/Analysis/src/TypePack.cpp b/Analysis/src/TypePack.cpp
index d4544483..2fa9413a 100644
--- a/Analysis/src/TypePack.cpp
+++ b/Analysis/src/TypePack.cpp
@@ -8,6 +8,13 @@
 namespace Luau
 {
 
+BlockedTypePack::BlockedTypePack()
+    : index(++nextIndex)
+{
+}
+
+size_t BlockedTypePack::nextIndex = 0;
+
 TypePackVar::TypePackVar(const TypePackVariant& tp)
     : ty(tp)
 {
diff --git a/Analysis/src/TypeUtils.cpp b/Analysis/src/TypeUtils.cpp
index 60bca0a3..56fccecc 100644
--- a/Analysis/src/TypeUtils.cpp
+++ b/Analysis/src/TypeUtils.cpp
@@ -84,9 +84,8 @@ std::optional<TypeId> findTablePropertyRespectingMeta(ErrorVec& errors, TypeId t
     return std::nullopt;
 }
 
-std::optional<TypeId> getIndexTypeFromType(
-    const ScopePtr& scope, ErrorVec& errors, TypeArena* arena, TypeId type, const std::string& prop, const Location& location, bool addErrors,
-    InternalErrorReporter& handle)
+std::optional<TypeId> getIndexTypeFromType(const ScopePtr& scope, ErrorVec& errors, TypeArena* arena, TypeId type, const std::string& prop,
+    const Location& location, bool addErrors, InternalErrorReporter& handle)
 {
     type = follow(type);
 
@@ -190,4 +189,33 @@ std::optional<TypeId> getIndexTypeFromType(
     return std::nullopt;
 }
 
+std::pair<size_t, std::optional<size_t>> getParameterExtents(const TxnLog* log, TypePackId tp)
+{
+    size_t minCount = 0;
+    size_t optionalCount = 0;
+
+    auto it = begin(tp, log);
+    auto endIter = end(tp);
+
+    while (it != endIter)
+    {
+        TypeId ty = *it;
+        if (isOptional(ty))
+            ++optionalCount;
+        else
+        {
+            minCount += optionalCount;
+            optionalCount = 0;
+            minCount++;
+        }
+
+        ++it;
+    }
+
+    if (it.tail())
+        return {minCount, std::nullopt};
+    else
+        return {minCount, minCount + optionalCount};
+}
+
 } // namespace Luau
diff --git a/Analysis/src/TypeVar.cpp b/Analysis/src/TypeVar.cpp
index 8974f8c7..4abee0f6 100644
--- a/Analysis/src/TypeVar.cpp
+++ b/Analysis/src/TypeVar.cpp
@@ -24,9 +24,7 @@ LUAU_FASTINTVARIABLE(LuauTypeMaximumStringifierLength, 500)
 LUAU_FASTINTVARIABLE(LuauTableTypeMaximumStringifierLength, 0)
 LUAU_FASTINT(LuauTypeInferRecursionLimit)
 LUAU_FASTFLAG(LuauUnknownAndNeverType)
-LUAU_FASTFLAGVARIABLE(LuauDeduceGmatchReturnTypes, false)
 LUAU_FASTFLAGVARIABLE(LuauMaybeGenericIntersectionTypes, false)
-LUAU_FASTFLAGVARIABLE(LuauDeduceFindMatchReturnTypes, false)
 LUAU_FASTFLAGVARIABLE(LuauStringFormatArgumentErrorFix, false)
 
 namespace Luau
@@ -446,8 +444,10 @@ BlockedTypeVar::BlockedTypeVar()
 
 int BlockedTypeVar::nextIndex = 0;
 
-PendingExpansionTypeVar::PendingExpansionTypeVar(TypeFun fn, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments)
-    : fn(fn)
+PendingExpansionTypeVar::PendingExpansionTypeVar(
+    std::optional<AstName> prefix, AstName name, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments)
+    : prefix(prefix)
+    , name(name)
     , typeArguments(typeArguments)
     , packArguments(packArguments)
     , index(++nextIndex)
@@ -787,8 +787,8 @@ TypeId SingletonTypes::makeStringMetatable()
         makeFunction(*arena, stringType, {}, {}, {stringType}, {}, {arena->addType(FunctionTypeVar{emptyPack, stringVariadicList})});
     attachMagicFunction(gmatchFunc, magicFunctionGmatch);
 
-    const TypeId matchFunc = arena->addType(FunctionTypeVar{arena->addTypePack({stringType, stringType, optionalNumber}),
-        arena->addTypePack(TypePackVar{VariadicTypePack{FFlag::LuauDeduceFindMatchReturnTypes ? stringType : optionalString}})});
+    const TypeId matchFunc = arena->addType(
+        FunctionTypeVar{arena->addTypePack({stringType, stringType, optionalNumber}), arena->addTypePack(TypePackVar{VariadicTypePack{stringType}})});
     attachMagicFunction(matchFunc, magicFunctionMatch);
 
     const TypeId findFunc = arena->addType(FunctionTypeVar{arena->addTypePack({stringType, stringType, optionalNumber, optionalBoolean}),
@@ -1221,9 +1221,6 @@ static std::vector<TypeId> parsePatternString(TypeChecker& typechecker, const ch
 static std::optional<WithPredicate<TypePackId>> magicFunctionGmatch(
     TypeChecker& typechecker, const ScopePtr& scope, const AstExprCall& expr, WithPredicate<TypePackId> withPredicate)
 {
-    if (!FFlag::LuauDeduceGmatchReturnTypes)
-        return std::nullopt;
-
     auto [paramPack, _predicates] = withPredicate;
     const auto& [params, tail] = flatten(paramPack);
 
@@ -1256,9 +1253,6 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionGmatch(
 static std::optional<WithPredicate<TypePackId>> magicFunctionMatch(
     TypeChecker& typechecker, const ScopePtr& scope, const AstExprCall& expr, WithPredicate<TypePackId> withPredicate)
 {
-    if (!FFlag::LuauDeduceFindMatchReturnTypes)
-        return std::nullopt;
-
     auto [paramPack, _predicates] = withPredicate;
     const auto& [params, tail] = flatten(paramPack);
 
@@ -1295,9 +1289,6 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionMatch(
 static std::optional<WithPredicate<TypePackId>> magicFunctionFind(
     TypeChecker& typechecker, const ScopePtr& scope, const AstExprCall& expr, WithPredicate<TypePackId> withPredicate)
 {
-    if (!FFlag::LuauDeduceFindMatchReturnTypes)
-        return std::nullopt;
-
     auto [paramPack, _predicates] = withPredicate;
     const auto& [params, tail] = flatten(paramPack);
 
diff --git a/Analysis/src/TypedAllocator.cpp b/Analysis/src/TypedAllocator.cpp
index 9ce8c3dc..c95c8eae 100644
--- a/Analysis/src/TypedAllocator.cpp
+++ b/Analysis/src/TypedAllocator.cpp
@@ -36,7 +36,9 @@ void* pagedAllocate(size_t size)
 {
     // By default we use operator new/delete instead of malloc/free so that they can be overridden externally
     if (!FFlag::DebugLuauFreezeArena)
+    {
         return ::operator new(size, std::nothrow);
+    }
 
     // On Windows, VirtualAlloc results in 64K granularity allocations; we allocate in chunks of ~32K so aligned_malloc is a little more efficient
     // On Linux, we must use mmap because using regular heap results in mprotect() fragmenting the page table and us bumping into 64K mmap limit.
diff --git a/Analysis/src/Unifiable.cpp b/Analysis/src/Unifiable.cpp
index 63d8647d..fa76e820 100644
--- a/Analysis/src/Unifiable.cpp
+++ b/Analysis/src/Unifiable.cpp
@@ -13,7 +13,8 @@ Free::Free(TypeLevel level)
 }
 
 Free::Free(Scope* scope)
-    : scope(scope)
+    : index(++nextIndex)
+    , scope(scope)
 {
 }
 
diff --git a/Analysis/src/Unifier.cpp b/Analysis/src/Unifier.cpp
index b5f58c83..b135cd0c 100644
--- a/Analysis/src/Unifier.cpp
+++ b/Analysis/src/Unifier.cpp
@@ -317,7 +317,8 @@ static std::optional<std::pair<Luau::Name, const SingletonTypeVar*>> getTableMat
     return std::nullopt;
 }
 
-Unifier::Unifier(TypeArena* types, Mode mode, NotNull<Scope> scope, const Location& location, Variance variance, UnifierSharedState& sharedState, TxnLog* parentLog)
+Unifier::Unifier(TypeArena* types, Mode mode, NotNull<Scope> scope, const Location& location, Variance variance, UnifierSharedState& sharedState,
+    TxnLog* parentLog)
     : types(types)
     , mode(mode)
     , scope(scope)
@@ -492,9 +493,9 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool
 
     if (log.get<ConstrainedTypeVar>(subTy))
         tryUnifyWithConstrainedSubTypeVar(subTy, superTy);
-    else if (const UnionTypeVar* uv = log.getMutable<UnionTypeVar>(subTy))
+    else if (const UnionTypeVar* subUnion = log.getMutable<UnionTypeVar>(subTy))
     {
-        tryUnifyUnionWithType(subTy, uv, superTy);
+        tryUnifyUnionWithType(subTy, subUnion, superTy);
     }
     else if (const UnionTypeVar* uv = log.getMutable<UnionTypeVar>(superTy))
     {
@@ -555,14 +556,14 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool
     log.popSeen(superTy, subTy);
 }
 
-void Unifier::tryUnifyUnionWithType(TypeId subTy, const UnionTypeVar* uv, TypeId superTy)
+void Unifier::tryUnifyUnionWithType(TypeId subTy, const UnionTypeVar* subUnion, TypeId superTy)
 {
     // A | B <: T if A <: T and B <: T
     bool failed = false;
     std::optional<TypeError> unificationTooComplex;
     std::optional<TypeError> firstFailedOption;
 
-    for (TypeId type : uv->options)
+    for (TypeId type : subUnion->options)
     {
         Unifier innerState = makeChildUnifier();
         innerState.tryUnify_(type, superTy);
@@ -608,9 +609,9 @@ void Unifier::tryUnifyUnionWithType(TypeId subTy, const UnionTypeVar* uv, TypeId
         }
     };
 
-    if (auto utv = log.getMutable<UnionTypeVar>(superTy))
+    if (auto superUnion = log.getMutable<UnionTypeVar>(superTy))
     {
-        for (TypeId ty : utv)
+        for (TypeId ty : superUnion)
             tryBind(ty);
     }
     else
diff --git a/Ast/include/Luau/Ast.h b/Ast/include/Luau/Ast.h
index 612283fb..07051163 100644
--- a/Ast/include/Luau/Ast.h
+++ b/Ast/include/Luau/Ast.h
@@ -1276,6 +1276,16 @@ public:
 };
 
 AstName getIdentifier(AstExpr*);
+Location getLocation(const AstTypeList& typeList);
+
+template<typename T> // AstNode, AstExpr, AstLocal, etc
+Location getLocation(AstArray<T*> array)
+{
+    if (0 == array.size)
+        return {};
+
+    return Location{array.data[0]->location.begin, array.data[array.size - 1]->location.end};
+}
 
 #undef LUAU_RTTI
 
diff --git a/Ast/include/Luau/Parser.h b/Ast/include/Luau/Parser.h
index 956fcf64..848d7117 100644
--- a/Ast/include/Luau/Parser.h
+++ b/Ast/include/Luau/Parser.h
@@ -304,6 +304,12 @@ private:
     AstExprError* reportExprError(const Location& location, const AstArray<AstExpr*>& expressions, const char* format, ...) LUAU_PRINTF_ATTR(4, 5);
     AstTypeError* reportTypeAnnotationError(const Location& location, const AstArray<AstType*>& types, bool isMissing, const char* format, ...)
         LUAU_PRINTF_ATTR(5, 6);
+    // `parseErrorLocation` is associated with the parser error
+    // `astErrorLocation` is associated with the AstTypeError created
+    // It can be useful to have different error locations so that the parse error can include the next lexeme, while the AstTypeError can precisely
+    // define the location (possibly of zero size) where a type annotation is expected.
+    AstTypeError* reportMissingTypeAnnotationError(const Location& parseErrorLocation, const Location& astErrorLocation, const char* format, ...)
+        LUAU_PRINTF_ATTR(4, 5);
 
     AstExpr* reportFunctionArgsError(AstExpr* func, bool self);
     void reportAmbiguousCallError();
diff --git a/Ast/src/Ast.cpp b/Ast/src/Ast.cpp
index 8291a5b1..cbed8bae 100644
--- a/Ast/src/Ast.cpp
+++ b/Ast/src/Ast.cpp
@@ -952,4 +952,17 @@ AstName getIdentifier(AstExpr* node)
     return AstName();
 }
 
+Location getLocation(const AstTypeList& typeList)
+{
+    Location result;
+    if (typeList.types.size)
+    {
+        result = Location{typeList.types.data[0]->location, typeList.types.data[typeList.types.size - 1]->location};
+    }
+    if (typeList.tailType)
+        result.end = typeList.tailType->location.end;
+
+    return result;
+}
+
 } // namespace Luau
diff --git a/Ast/src/Lexer.cpp b/Ast/src/Lexer.cpp
index b4db8bdf..d93f2ccb 100644
--- a/Ast/src/Lexer.cpp
+++ b/Ast/src/Lexer.cpp
@@ -91,18 +91,8 @@ Lexeme::Lexeme(const Location& location, Type type, const char* data, size_t siz
     , length(unsigned(size))
     , data(data)
 {
-    LUAU_ASSERT(
-        type == RawString
-        || type == QuotedString
-        || type == InterpStringBegin
-        || type == InterpStringMid
-        || type == InterpStringEnd
-        || type == InterpStringSimple
-        || type == BrokenInterpDoubleBrace
-        || type == Number
-        || type == Comment
-        || type == BlockComment
-    );
+    LUAU_ASSERT(type == RawString || type == QuotedString || type == InterpStringBegin || type == InterpStringMid || type == InterpStringEnd ||
+                type == InterpStringSimple || type == BrokenInterpDoubleBrace || type == Number || type == Comment || type == BlockComment);
 }
 
 Lexeme::Lexeme(const Location& location, Type type, const char* name)
@@ -644,7 +634,8 @@ Lexeme Lexer::readInterpolatedStringSection(Position start, Lexeme::Type formatT
 
             if (peekch(1) == '{')
             {
-                Lexeme brokenDoubleBrace = Lexeme(Location(start, position()), Lexeme::BrokenInterpDoubleBrace, &buffer[startOffset], offset - startOffset);
+                Lexeme brokenDoubleBrace =
+                    Lexeme(Location(start, position()), Lexeme::BrokenInterpDoubleBrace, &buffer[startOffset], offset - startOffset);
                 consume();
                 consume();
                 return brokenDoubleBrace;
diff --git a/Ast/src/Parser.cpp b/Ast/src/Parser.cpp
index b6de27da..0914054f 100644
--- a/Ast/src/Parser.cpp
+++ b/Ast/src/Parser.cpp
@@ -24,6 +24,7 @@ LUAU_FASTFLAGVARIABLE(LuauLintParseIntegerIssues, false)
 LUAU_DYNAMIC_FASTFLAGVARIABLE(LuaReportParseIntegerIssues, false)
 
 LUAU_FASTFLAGVARIABLE(LuauInterpolatedStringBaseSupport, false)
+LUAU_FASTFLAGVARIABLE(LuauTypeAnnotationLocationChange, false)
 
 bool lua_telemetry_parsed_out_of_range_bin_integer = false;
 bool lua_telemetry_parsed_out_of_range_hex_integer = false;
@@ -1564,44 +1565,43 @@ AstTypeOrPack Parser::parseSimpleTypeAnnotation(bool allowPack)
 {
     incrementRecursionCounter("type annotation");
 
-    Location begin = lexer.current().location;
+    Location start = lexer.current().location;
 
     if (lexer.current().type == Lexeme::ReservedNil)
     {
         nextLexeme();
-        return {allocator.alloc<AstTypeReference>(begin, std::nullopt, nameNil), {}};
+        return {allocator.alloc<AstTypeReference>(start, std::nullopt, nameNil), {}};
     }
     else if (lexer.current().type == Lexeme::ReservedTrue)
     {
         nextLexeme();
-        return {allocator.alloc<AstTypeSingletonBool>(begin, true)};
+        return {allocator.alloc<AstTypeSingletonBool>(start, true)};
     }
     else if (lexer.current().type == Lexeme::ReservedFalse)
     {
         nextLexeme();
-        return {allocator.alloc<AstTypeSingletonBool>(begin, false)};
+        return {allocator.alloc<AstTypeSingletonBool>(start, false)};
     }
     else if (lexer.current().type == Lexeme::RawString || lexer.current().type == Lexeme::QuotedString)
     {
         if (std::optional<AstArray<char>> value = parseCharArray())
         {
             AstArray<char> svalue = *value;
-            return {allocator.alloc<AstTypeSingletonString>(begin, svalue)};
+            return {allocator.alloc<AstTypeSingletonString>(start, svalue)};
         }
         else
-            return {reportTypeAnnotationError(begin, {}, /*isMissing*/ false, "String literal contains malformed escape sequence")};
+            return {reportTypeAnnotationError(start, {}, /*isMissing*/ false, "String literal contains malformed escape sequence")};
     }
     else if (lexer.current().type == Lexeme::InterpStringBegin || lexer.current().type == Lexeme::InterpStringSimple)
     {
         parseInterpString();
 
-        return {reportTypeAnnotationError(begin, {}, /*isMissing*/ false, "Interpolated string literals cannot be used as types")};
+        return {reportTypeAnnotationError(start, {}, /*isMissing*/ false, "Interpolated string literals cannot be used as types")};
     }
     else if (lexer.current().type == Lexeme::BrokenString)
     {
-        Location location = lexer.current().location;
         nextLexeme();
-        return {reportTypeAnnotationError(location, {}, /*isMissing*/ false, "Malformed string")};
+        return {reportTypeAnnotationError(start, {}, /*isMissing*/ false, "Malformed string")};
     }
     else if (lexer.current().type == Lexeme::Name)
     {
@@ -1632,7 +1632,7 @@ AstTypeOrPack Parser::parseSimpleTypeAnnotation(bool allowPack)
 
             expectMatchAndConsume(')', typeofBegin);
 
-            return {allocator.alloc<AstTypeTypeof>(Location(begin, end), expr), {}};
+            return {allocator.alloc<AstTypeTypeof>(Location(start, end), expr), {}};
         }
 
         bool hasParameters = false;
@@ -1646,7 +1646,7 @@ AstTypeOrPack Parser::parseSimpleTypeAnnotation(bool allowPack)
 
         Location end = lexer.previousLocation();
 
-        return {allocator.alloc<AstTypeReference>(Location(begin, end), prefix, name.name, hasParameters, parameters), {}};
+        return {allocator.alloc<AstTypeReference>(Location(start, end), prefix, name.name, hasParameters, parameters), {}};
     }
     else if (lexer.current().type == '{')
     {
@@ -1658,23 +1658,35 @@ AstTypeOrPack Parser::parseSimpleTypeAnnotation(bool allowPack)
     }
     else if (lexer.current().type == Lexeme::ReservedFunction)
     {
-        Location location = lexer.current().location;
-
         nextLexeme();
 
-        return {reportTypeAnnotationError(location, {}, /*isMissing*/ false,
+        return {reportTypeAnnotationError(start, {}, /*isMissing*/ false,
                     "Using 'function' as a type annotation is not supported, consider replacing with a function type annotation e.g. '(...any) -> "
                     "...any'"),
             {}};
     }
     else
     {
-        Location location = lexer.current().location;
+        if (FFlag::LuauTypeAnnotationLocationChange)
+        {
+            // For a missing type annotation, capture 'space' between last token and the next one
+            Location astErrorlocation(lexer.previousLocation().end, start.begin);
+            // The parse error includes the next lexeme to make it easier to display where the error is (e.g. in an IDE or a CLI error message).
+            // Including the current lexeme also makes the parse error consistent with other parse errors returned by Luau.
+            Location parseErrorLocation(lexer.previousLocation().end, start.end);
+            return {
+                reportMissingTypeAnnotationError(parseErrorLocation, astErrorlocation, "Expected type, got %s", lexer.current().toString().c_str()),
+                {}};
+        }
+        else
+        {
+            Location location = lexer.current().location;
 
-        // For a missing type annotation, capture 'space' between last token and the next one
-        location = Location(lexer.previousLocation().end, lexer.current().location.begin);
+            // For a missing type annotation, capture 'space' between last token and the next one
+            location = Location(lexer.previousLocation().end, lexer.current().location.begin);
 
-        return {reportTypeAnnotationError(location, {}, /*isMissing*/ true, "Expected type, got %s", lexer.current().toString().c_str()), {}};
+            return {reportTypeAnnotationError(location, {}, /*isMissing*/ true, "Expected type, got %s", lexer.current().toString().c_str()), {}};
+        }
     }
 }
 
@@ -2245,7 +2257,8 @@ AstExpr* Parser::parseSimpleExpr()
     {
         return parseNumber();
     }
-    else if (lexer.current().type == Lexeme::RawString || lexer.current().type == Lexeme::QuotedString || (FFlag::LuauInterpolatedStringBaseSupport && lexer.current().type == Lexeme::InterpStringSimple))
+    else if (lexer.current().type == Lexeme::RawString || lexer.current().type == Lexeme::QuotedString ||
+             (FFlag::LuauInterpolatedStringBaseSupport && lexer.current().type == Lexeme::InterpStringSimple))
     {
         return parseString();
     }
@@ -2653,7 +2666,8 @@ AstArray<AstTypeOrPack> Parser::parseTypeParams()
 
 std::optional<AstArray<char>> Parser::parseCharArray()
 {
-    LUAU_ASSERT(lexer.current().type == Lexeme::QuotedString || lexer.current().type == Lexeme::RawString || lexer.current().type == Lexeme::InterpStringSimple);
+    LUAU_ASSERT(lexer.current().type == Lexeme::QuotedString || lexer.current().type == Lexeme::RawString ||
+                lexer.current().type == Lexeme::InterpStringSimple);
 
     scratchData.assign(lexer.current().data, lexer.current().length);
 
@@ -2691,14 +2705,11 @@ AstExpr* Parser::parseInterpString()
 
     Location startLocation = lexer.current().location;
 
-    do {
+    do
+    {
         Lexeme currentLexeme = lexer.current();
-        LUAU_ASSERT(
-            currentLexeme.type == Lexeme::InterpStringBegin
-            || currentLexeme.type == Lexeme::InterpStringMid
-            || currentLexeme.type == Lexeme::InterpStringEnd
-            || currentLexeme.type == Lexeme::InterpStringSimple
-        );
+        LUAU_ASSERT(currentLexeme.type == Lexeme::InterpStringBegin || currentLexeme.type == Lexeme::InterpStringMid ||
+                    currentLexeme.type == Lexeme::InterpStringEnd || currentLexeme.type == Lexeme::InterpStringSimple);
 
         Location location = currentLexeme.location;
 
@@ -2973,8 +2984,7 @@ bool Parser::expectMatchEndAndConsume(Lexeme::Type type, const MatchLexeme& begi
     {
         // If the token matches on a different line and a different column, it suggests misleading indentation
         // This can be used to pinpoint the problem location for a possible future *actual* mismatch
-        if (lexer.current().location.begin.line != begin.position.line &&
-            lexer.current().location.begin.column != begin.position.column &&
+        if (lexer.current().location.begin.line != begin.position.line && lexer.current().location.begin.column != begin.position.column &&
             endMismatchSuspect.position.line < begin.position.line) // Only replace the previous suspect with more recent suspects
         {
             endMismatchSuspect = begin;
@@ -3108,6 +3118,13 @@ AstExprError* Parser::reportExprError(const Location& location, const AstArray<A
 
 AstTypeError* Parser::reportTypeAnnotationError(const Location& location, const AstArray<AstType*>& types, bool isMissing, const char* format, ...)
 {
+    if (FFlag::LuauTypeAnnotationLocationChange)
+    {
+        // Missing type annotations should be using `reportMissingTypeAnnotationError` when LuauTypeAnnotationLocationChange is enabled
+        // Note: `isMissing` can be removed once FFlag::LuauTypeAnnotationLocationChange is removed since it will always be true.
+        LUAU_ASSERT(!isMissing);
+    }
+
     va_list args;
     va_start(args, format);
     report(location, format, args);
@@ -3116,6 +3133,18 @@ AstTypeError* Parser::reportTypeAnnotationError(const Location& location, const
     return allocator.alloc<AstTypeError>(location, types, isMissing, unsigned(parseErrors.size() - 1));
 }
 
+AstTypeError* Parser::reportMissingTypeAnnotationError(const Location& parseErrorLocation, const Location& astErrorLocation, const char* format, ...)
+{
+    LUAU_ASSERT(FFlag::LuauTypeAnnotationLocationChange);
+
+    va_list args;
+    va_start(args, format);
+    report(parseErrorLocation, format, args);
+    va_end(args);
+
+    return allocator.alloc<AstTypeError>(astErrorLocation, AstArray<AstType*>{}, true, unsigned(parseErrors.size() - 1));
+}
+
 void Parser::nextLexeme()
 {
     Lexeme::Type type = lexer.next(/* skipComments= */ false, true).type;
diff --git a/Common/include/Luau/Bytecode.h b/Common/include/Luau/Bytecode.h
index d6660f05..decde93f 100644
--- a/Common/include/Luau/Bytecode.h
+++ b/Common/include/Luau/Bytecode.h
@@ -414,7 +414,7 @@ enum LuauBytecodeTag
     // Bytecode version; runtime supports [MIN, MAX], compiler emits TARGET by default but may emit a higher version when flags are enabled
     LBC_VERSION_MIN = 2,
     LBC_VERSION_MAX = 3,
-    LBC_VERSION_TARGET = 2,
+    LBC_VERSION_TARGET = 3,
     // Types of constant table entries
     LBC_CONSTANT_NIL = 0,
     LBC_CONSTANT_BOOLEAN,
diff --git a/Common/include/Luau/ExperimentalFlags.h b/Common/include/Luau/ExperimentalFlags.h
index 809c78da..ce47cd9a 100644
--- a/Common/include/Luau/ExperimentalFlags.h
+++ b/Common/include/Luau/ExperimentalFlags.h
@@ -13,7 +13,8 @@ inline bool isFlagExperimental(const char* flag)
     static const char* kList[] = {
         "LuauLowerBoundsCalculation",
         "LuauInterpolatedStringBaseSupport",
-        nullptr, // makes sure we always have at least one entry
+        // makes sure we always have at least one entry
+        nullptr,
     };
 
     for (const char* item : kList)
diff --git a/Compiler/src/BytecodeBuilder.cpp b/Compiler/src/BytecodeBuilder.cpp
index 46ab2648..713d08cd 100644
--- a/Compiler/src/BytecodeBuilder.cpp
+++ b/Compiler/src/BytecodeBuilder.cpp
@@ -6,8 +6,6 @@
 #include <algorithm>
 #include <string.h>
 
-LUAU_FASTFLAGVARIABLE(LuauCompileBytecodeV3, false)
-
 namespace Luau
 {
 
@@ -1079,9 +1077,6 @@ std::string BytecodeBuilder::getError(const std::string& message)
 
 uint8_t BytecodeBuilder::getVersion()
 {
-    if (FFlag::LuauCompileBytecodeV3)
-        return 3;
-
     // This function usually returns LBC_VERSION_TARGET but may sometimes return a higher number (within LBC_VERSION_MIN/MAX) under fast flags
     return LBC_VERSION_TARGET;
 }
diff --git a/Compiler/src/Compiler.cpp b/Compiler/src/Compiler.cpp
index 4429e4cc..d44daf0c 100644
--- a/Compiler/src/Compiler.cpp
+++ b/Compiler/src/Compiler.cpp
@@ -25,14 +25,8 @@ LUAU_FASTINTVARIABLE(LuauCompileInlineThreshold, 25)
 LUAU_FASTINTVARIABLE(LuauCompileInlineThresholdMaxBoost, 300)
 LUAU_FASTINTVARIABLE(LuauCompileInlineDepth, 5)
 
-LUAU_FASTFLAGVARIABLE(LuauCompileXEQ, false)
-
 LUAU_FASTFLAG(LuauInterpolatedStringBaseSupport)
 
-LUAU_FASTFLAGVARIABLE(LuauCompileOptimalAssignment, false)
-
-LUAU_FASTFLAGVARIABLE(LuauCompileExtractK, false)
-
 namespace Luau
 {
 
@@ -406,47 +400,29 @@ struct Compiler
         }
     }
 
-    void compileExprFastcallN(AstExprCall* expr, uint8_t target, uint8_t targetCount, bool targetTop, bool multRet, uint8_t regs, int bfid, int bfK = -1)
+    void compileExprFastcallN(
+        AstExprCall* expr, uint8_t target, uint8_t targetCount, bool targetTop, bool multRet, uint8_t regs, int bfid, int bfK = -1)
     {
         LUAU_ASSERT(!expr->self);
         LUAU_ASSERT(expr->args.size >= 1);
         LUAU_ASSERT(expr->args.size <= 2 || (bfid == LBF_BIT32_EXTRACTK && expr->args.size == 3));
         LUAU_ASSERT(bfid == LBF_BIT32_EXTRACTK ? bfK >= 0 : bfK < 0);
 
-        LuauOpcode opc = expr->args.size == 1 ? LOP_FASTCALL1 : LOP_FASTCALL2;
-
-        if (FFlag::LuauCompileExtractK)
-        {
-            opc = expr->args.size == 1 ? LOP_FASTCALL1 : (bfK >= 0 || isConstant(expr->args.data[1])) ? LOP_FASTCALL2K : LOP_FASTCALL2;
-        }
+        LuauOpcode opc = expr->args.size == 1 ? LOP_FASTCALL1 : (bfK >= 0 || isConstant(expr->args.data[1])) ? LOP_FASTCALL2K : LOP_FASTCALL2;
 
         uint32_t args[3] = {};
 
         for (size_t i = 0; i < expr->args.size; ++i)
         {
-            if (FFlag::LuauCompileExtractK)
+            if (i > 0 && opc == LOP_FASTCALL2K)
             {
-                if (i > 0 && opc == LOP_FASTCALL2K)
-                {
-                    int32_t cid = getConstantIndex(expr->args.data[i]);
-                    if (cid < 0)
-                        CompileError::raise(expr->location, "Exceeded constant limit; simplify the code to compile");
+                int32_t cid = getConstantIndex(expr->args.data[i]);
+                if (cid < 0)
+                    CompileError::raise(expr->location, "Exceeded constant limit; simplify the code to compile");
 
-                    args[i] = cid;
-                    continue; // TODO: remove this and change if below to else if
-                }
+                args[i] = cid;
             }
-            else if (i > 0)
-            {
-                if (int32_t cid = getConstantIndex(expr->args.data[i]); cid >= 0)
-                {
-                    opc = LOP_FASTCALL2K;
-                    args[i] = cid;
-                    break;
-                }
-            }
-
-            if (int reg = getExprLocalReg(expr->args.data[i]); reg >= 0)
+            else if (int reg = getExprLocalReg(expr->args.data[i]); reg >= 0)
             {
                 args[i] = uint8_t(reg);
             }
@@ -468,24 +444,10 @@ struct Compiler
         // these FASTCALL variants.
         for (size_t i = 0; i < expr->args.size; ++i)
         {
-            if (FFlag::LuauCompileExtractK)
-            {
-                if (i > 0 && opc == LOP_FASTCALL2K)
-                    emitLoadK(uint8_t(regs + 1 + i), args[i]);
-                else if (args[i] != regs + 1 + i)
-                    bytecode.emitABC(LOP_MOVE, uint8_t(regs + 1 + i), uint8_t(args[i]), 0);
-            }
-            else
-            {
-                if (i > 0 && opc == LOP_FASTCALL2K)
-                {
-                    emitLoadK(uint8_t(regs + 1 + i), args[i]);
-                    break;
-                }
-
-                if (args[i] != regs + 1 + i)
-                    bytecode.emitABC(LOP_MOVE, uint8_t(regs + 1 + i), uint8_t(args[i]), 0);
-            }
+            if (i > 0 && opc == LOP_FASTCALL2K)
+                emitLoadK(uint8_t(regs + 1 + i), args[i]);
+            else if (args[i] != regs + 1 + i)
+                bytecode.emitABC(LOP_MOVE, uint8_t(regs + 1 + i), uint8_t(args[i]), 0);
         }
 
         // note, these instructions are normally not executed and are used as a fallback for FASTCALL
@@ -758,7 +720,7 @@ struct Compiler
         }
 
         // Optimization: for bit32.extract with constant in-range f/w we compile using FASTCALL2K and a special builtin
-        if (FFlag::LuauCompileExtractK && bfid == LBF_BIT32_EXTRACT && expr->args.size == 3 && isConstant(expr->args.data[1]) && isConstant(expr->args.data[2]))
+        if (bfid == LBF_BIT32_EXTRACT && expr->args.size == 3 && isConstant(expr->args.data[1]) && isConstant(expr->args.data[2]))
         {
             Constant fc = getConstant(expr->args.data[1]);
             Constant wc = getConstant(expr->args.data[2]);
@@ -1080,102 +1042,64 @@ struct Compiler
                 std::swap(left, right);
         }
 
-        if (FFlag::LuauCompileXEQ)
+        uint8_t rl = compileExprAuto(left, rs);
+
+        if (isEq && operandIsConstant)
         {
-            uint8_t rl = compileExprAuto(left, rs);
+            const Constant* cv = constants.find(right);
+            LUAU_ASSERT(cv && cv->type != Constant::Type_Unknown);
 
-            if (isEq && operandIsConstant)
+            LuauOpcode opc = LOP_NOP;
+            int32_t cid = -1;
+            uint32_t flip = (expr->op == AstExprBinary::CompareEq) == not_ ? 0x80000000 : 0;
+
+            switch (cv->type)
             {
-                const Constant* cv = constants.find(right);
-                LUAU_ASSERT(cv && cv->type != Constant::Type_Unknown);
+            case Constant::Type_Nil:
+                opc = LOP_JUMPXEQKNIL;
+                cid = 0;
+                break;
 
-                LuauOpcode opc = LOP_NOP;
-                int32_t cid = -1;
-                uint32_t flip = (expr->op == AstExprBinary::CompareEq) == not_ ? 0x80000000 : 0;
+            case Constant::Type_Boolean:
+                opc = LOP_JUMPXEQKB;
+                cid = cv->valueBoolean;
+                break;
 
-                switch (cv->type)
-                {
-                case Constant::Type_Nil:
-                    opc = LOP_JUMPXEQKNIL;
-                    cid = 0;
-                    break;
+            case Constant::Type_Number:
+                opc = LOP_JUMPXEQKN;
+                cid = getConstantIndex(right);
+                break;
 
-                case Constant::Type_Boolean:
-                    opc = LOP_JUMPXEQKB;
-                    cid = cv->valueBoolean;
-                    break;
+            case Constant::Type_String:
+                opc = LOP_JUMPXEQKS;
+                cid = getConstantIndex(right);
+                break;
 
-                case Constant::Type_Number:
-                    opc = LOP_JUMPXEQKN;
-                    cid = getConstantIndex(right);
-                    break;
-
-                case Constant::Type_String:
-                    opc = LOP_JUMPXEQKS;
-                    cid = getConstantIndex(right);
-                    break;
-
-                default:
-                    LUAU_ASSERT(!"Unexpected constant type");
-                }
-
-                if (cid < 0)
-                    CompileError::raise(expr->location, "Exceeded constant limit; simplify the code to compile");
-
-                size_t jumpLabel = bytecode.emitLabel();
-
-                bytecode.emitAD(opc, rl, 0);
-                bytecode.emitAux(cid | flip);
-
-                return jumpLabel;
+            default:
+                LUAU_ASSERT(!"Unexpected constant type");
             }
-            else
-            {
-                LuauOpcode opc = getJumpOpCompare(expr->op, not_);
 
-                uint8_t rr = compileExprAuto(right, rs);
+            if (cid < 0)
+                CompileError::raise(expr->location, "Exceeded constant limit; simplify the code to compile");
 
-                size_t jumpLabel = bytecode.emitLabel();
+            size_t jumpLabel = bytecode.emitLabel();
 
-                if (expr->op == AstExprBinary::CompareGt || expr->op == AstExprBinary::CompareGe)
-                {
-                    bytecode.emitAD(opc, rr, 0);
-                    bytecode.emitAux(rl);
-                }
-                else
-                {
-                    bytecode.emitAD(opc, rl, 0);
-                    bytecode.emitAux(rr);
-                }
+            bytecode.emitAD(opc, rl, 0);
+            bytecode.emitAux(cid | flip);
 
-                return jumpLabel;
-            }
+            return jumpLabel;
         }
         else
         {
             LuauOpcode opc = getJumpOpCompare(expr->op, not_);
 
-            uint8_t rl = compileExprAuto(left, rs);
-            int32_t rr = -1;
-
-            if (isEq && operandIsConstant)
-            {
-                if (opc == LOP_JUMPIFEQ)
-                    opc = LOP_JUMPIFEQK;
-                else if (opc == LOP_JUMPIFNOTEQ)
-                    opc = LOP_JUMPIFNOTEQK;
-
-                rr = getConstantIndex(right);
-                LUAU_ASSERT(rr >= 0);
-            }
-            else
-                rr = compileExprAuto(right, rs);
+            uint8_t rr = compileExprAuto(right, rs);
 
             size_t jumpLabel = bytecode.emitLabel();
 
             if (expr->op == AstExprBinary::CompareGt || expr->op == AstExprBinary::CompareGe)
             {
-                bytecode.emitAD(opc, uint8_t(rr), 0);
+                bytecode.emitAD(opc, rr, 0);
                 bytecode.emitAux(rl);
             }
             else
@@ -2979,62 +2903,6 @@ struct Compiler
         loops.pop_back();
     }
 
-    void resolveAssignConflicts(AstStat* stat, std::vector<LValue>& vars)
-    {
-        LUAU_ASSERT(!FFlag::LuauCompileOptimalAssignment);
-
-        // regsUsed[i] is true if we have assigned the register during earlier assignments
-        // regsRemap[i] is set to the register where the original (pre-assignment) copy was made
-        // note: regsRemap is uninitialized intentionally to speed small assignments up; regsRemap[i] is valid iff regsUsed[i]
-        std::bitset<256> regsUsed;
-        uint8_t regsRemap[256];
-
-        for (size_t i = 0; i < vars.size(); ++i)
-        {
-            LValue& li = vars[i];
-
-            if (li.kind == LValue::Kind_Local)
-            {
-                if (!regsUsed[li.reg])
-                {
-                    regsUsed[li.reg] = true;
-                    regsRemap[li.reg] = li.reg;
-                }
-            }
-            else if (li.kind == LValue::Kind_IndexName || li.kind == LValue::Kind_IndexNumber || li.kind == LValue::Kind_IndexExpr)
-            {
-                // we're looking for assignments before this one that invalidate any of the registers involved
-                if (regsUsed[li.reg])
-                {
-                    // the register may have been evacuated previously, but if it wasn't - move it now
-                    if (regsRemap[li.reg] == li.reg)
-                    {
-                        uint8_t reg = allocReg(stat, 1);
-                        bytecode.emitABC(LOP_MOVE, reg, li.reg, 0);
-
-                        regsRemap[li.reg] = reg;
-                    }
-
-                    li.reg = regsRemap[li.reg];
-                }
-
-                if (li.kind == LValue::Kind_IndexExpr && regsUsed[li.index])
-                {
-                    // the register may have been evacuated previously, but if it wasn't - move it now
-                    if (regsRemap[li.index] == li.index)
-                    {
-                        uint8_t reg = allocReg(stat, 1);
-                        bytecode.emitABC(LOP_MOVE, reg, li.index, 0);
-
-                        regsRemap[li.index] = reg;
-                    }
-
-                    li.index = regsRemap[li.index];
-                }
-            }
-        }
-    }
-
     struct Assignment
     {
         LValue lvalue;
@@ -3146,111 +3014,82 @@ struct Compiler
             return;
         }
 
-        if (FFlag::LuauCompileOptimalAssignment)
+        // compute all l-values: note that this doesn't assign anything yet but it allocates registers and computes complex expressions on the
+        // left hand side - for example, in "a[expr] = foo" expr will get evaluated here
+        std::vector<Assignment> vars(stat->vars.size);
+
+        for (size_t i = 0; i < stat->vars.size; ++i)
+            vars[i].lvalue = compileLValue(stat->vars.data[i], rs);
+
+        // perform conflict resolution: if any expression refers to a local that is assigned before evaluating it, we assign to a temporary
+        // register after this, vars[i].conflictReg is set for locals that need to be assigned in the second pass
+        resolveAssignConflicts(stat, vars, stat->values);
+
+        // compute rhs into (mostly) fresh registers
+        // note that when the lhs assigment is a local, we evaluate directly into that register
+        // this is possible because resolveAssignConflicts renamed conflicting locals into temporaries
+        // after this, vars[i].valueReg is set to a register with the value for *all* vars, but some have already been assigned
+        for (size_t i = 0; i < stat->vars.size && i < stat->values.size; ++i)
         {
-            // compute all l-values: note that this doesn't assign anything yet but it allocates registers and computes complex expressions on the
-            // left hand side - for example, in "a[expr] = foo" expr will get evaluated here
-            std::vector<Assignment> vars(stat->vars.size);
+            AstExpr* value = stat->values.data[i];
 
-            for (size_t i = 0; i < stat->vars.size; ++i)
-                vars[i].lvalue = compileLValue(stat->vars.data[i], rs);
-
-            // perform conflict resolution: if any expression refers to a local that is assigned before evaluating it, we assign to a temporary
-            // register after this, vars[i].conflictReg is set for locals that need to be assigned in the second pass
-            resolveAssignConflicts(stat, vars, stat->values);
-
-            // compute rhs into (mostly) fresh registers
-            // note that when the lhs assigment is a local, we evaluate directly into that register
-            // this is possible because resolveAssignConflicts renamed conflicting locals into temporaries
-            // after this, vars[i].valueReg is set to a register with the value for *all* vars, but some have already been assigned
-            for (size_t i = 0; i < stat->vars.size && i < stat->values.size; ++i)
+            if (i + 1 == stat->values.size && stat->vars.size > stat->values.size)
             {
-                AstExpr* value = stat->values.data[i];
+                // allocate a consecutive range of regs for all remaining vars and compute everything into temps
+                // note, this also handles trailing nils
+                uint8_t rest = uint8_t(stat->vars.size - stat->values.size + 1);
+                uint8_t temp = allocReg(stat, rest);
 
-                if (i + 1 == stat->values.size && stat->vars.size > stat->values.size)
+                compileExprTempN(value, temp, rest, /* targetTop= */ true);
+
+                for (size_t j = i; j < stat->vars.size; ++j)
+                    vars[j].valueReg = uint8_t(temp + (j - i));
+            }
+            else
+            {
+                Assignment& var = vars[i];
+
+                // if target is a local, use compileExpr directly to target
+                if (var.lvalue.kind == LValue::Kind_Local)
                 {
-                    // allocate a consecutive range of regs for all remaining vars and compute everything into temps
-                    // note, this also handles trailing nils
-                    uint8_t rest = uint8_t(stat->vars.size - stat->values.size + 1);
-                    uint8_t temp = allocReg(stat, rest);
+                    var.valueReg = (var.conflictReg == kInvalidReg) ? var.lvalue.reg : var.conflictReg;
 
-                    compileExprTempN(value, temp, rest, /* targetTop= */ true);
-
-                    for (size_t j = i; j < stat->vars.size; ++j)
-                        vars[j].valueReg = uint8_t(temp + (j - i));
+                    compileExpr(stat->values.data[i], var.valueReg);
                 }
                 else
                 {
-                    Assignment& var = vars[i];
-
-                    // if target is a local, use compileExpr directly to target
-                    if (var.lvalue.kind == LValue::Kind_Local)
-                    {
-                        var.valueReg = (var.conflictReg == kInvalidReg) ? var.lvalue.reg : var.conflictReg;
-
-                        compileExpr(stat->values.data[i], var.valueReg);
-                    }
-                    else
-                    {
-                        var.valueReg = compileExprAuto(stat->values.data[i], rs);
-                    }
+                    var.valueReg = compileExprAuto(stat->values.data[i], rs);
                 }
             }
-
-            // compute expressions with side effects for lulz
-            for (size_t i = stat->vars.size; i < stat->values.size; ++i)
-            {
-                RegScope rsi(this);
-                compileExprAuto(stat->values.data[i], rsi);
-            }
-
-            // almost done... let's assign everything left to right, noting that locals were either written-to directly, or will be written-to in a
-            // separate pass to avoid conflicts
-            for (const Assignment& var : vars)
-            {
-                LUAU_ASSERT(var.valueReg != kInvalidReg);
-
-                if (var.lvalue.kind != LValue::Kind_Local)
-                {
-                    setDebugLine(var.lvalue.location);
-                    compileAssign(var.lvalue, var.valueReg);
-                }
-            }
-
-            // all regular local writes are done by the prior loops by computing result directly into target, so this just handles conflicts OR
-            // local copies from temporary registers in multret context, since in that case we have to allocate consecutive temporaries
-            for (const Assignment& var : vars)
-            {
-                if (var.lvalue.kind == LValue::Kind_Local && var.valueReg != var.lvalue.reg)
-                    bytecode.emitABC(LOP_MOVE, var.lvalue.reg, var.valueReg, 0);
-            }
         }
-        else
+
+        // compute expressions with side effects for lulz
+        for (size_t i = stat->vars.size; i < stat->values.size; ++i)
         {
-            // compute all l-values: note that this doesn't assign anything yet but it allocates registers and computes complex expressions on the
-            // left hand side for example, in "a[expr] = foo" expr will get evaluated here
-            std::vector<LValue> vars(stat->vars.size);
+            RegScope rsi(this);
+            compileExprAuto(stat->values.data[i], rsi);
+        }
 
-            for (size_t i = 0; i < stat->vars.size; ++i)
-                vars[i] = compileLValue(stat->vars.data[i], rs);
+        // almost done... let's assign everything left to right, noting that locals were either written-to directly, or will be written-to in a
+        // separate pass to avoid conflicts
+        for (const Assignment& var : vars)
+        {
+            LUAU_ASSERT(var.valueReg != kInvalidReg);
 
-            // perform conflict resolution: if any lvalue refers to a local reg that will be reassigned before that, we save the local variable in a
-            // temporary reg
-            resolveAssignConflicts(stat, vars);
-
-            // compute values into temporaries
-            uint8_t regs = allocReg(stat, unsigned(stat->vars.size));
-
-            compileExprListTemp(stat->values, regs, uint8_t(stat->vars.size), /* targetTop= */ true);
-
-            // assign variables that have associated values; note that if we have fewer values than variables, we'll assign nil because
-            // compileExprListTemp will generate nils
-            for (size_t i = 0; i < stat->vars.size; ++i)
+            if (var.lvalue.kind != LValue::Kind_Local)
             {
-                setDebugLine(stat->vars.data[i]);
-                compileAssign(vars[i], uint8_t(regs + i));
+                setDebugLine(var.lvalue.location);
+                compileAssign(var.lvalue, var.valueReg);
             }
         }
+
+        // all regular local writes are done by the prior loops by computing result directly into target, so this just handles conflicts OR
+        // local copies from temporary registers in multret context, since in that case we have to allocate consecutive temporaries
+        for (const Assignment& var : vars)
+        {
+            if (var.lvalue.kind == LValue::Kind_Local && var.valueReg != var.lvalue.reg)
+                bytecode.emitABC(LOP_MOVE, var.lvalue.reg, var.valueReg, 0);
+        }
     }
 
     void compileStatCompoundAssign(AstStatCompoundAssign* stat)
diff --git a/VM/src/lbuiltins.cpp b/VM/src/lbuiltins.cpp
index 422c82b1..c16e5aa7 100644
--- a/VM/src/lbuiltins.cpp
+++ b/VM/src/lbuiltins.cpp
@@ -15,8 +15,6 @@
 #include <intrin.h>
 #endif
 
-LUAU_FASTFLAGVARIABLE(LuauFasterBit32NoWidth, false)
-
 // luauF functions implement FASTCALL instruction that performs a direct execution of some builtin functions from the VM
 // The rule of thumb is that FASTCALL functions can not call user code, yield, fail, or reallocate stack.
 // If types of the arguments mismatch, luauF_* needs to return -1 and the execution will fall back to the usual call path
@@ -602,7 +600,7 @@ static int luauF_btest(lua_State* L, StkId res, TValue* arg0, int nresults, StkI
 
 static int luauF_extract(lua_State* L, StkId res, TValue* arg0, int nresults, StkId args, int nparams)
 {
-    if (nparams >= (3 - FFlag::LuauFasterBit32NoWidth) && nresults <= 1 && ttisnumber(arg0) && ttisnumber(args))
+    if (nparams >= 2 && nresults <= 1 && ttisnumber(arg0) && ttisnumber(args))
     {
         double a1 = nvalue(arg0);
         double a2 = nvalue(args);
@@ -693,7 +691,7 @@ static int luauF_lshift(lua_State* L, StkId res, TValue* arg0, int nresults, Stk
 
 static int luauF_replace(lua_State* L, StkId res, TValue* arg0, int nresults, StkId args, int nparams)
 {
-    if (nparams >= (4 - FFlag::LuauFasterBit32NoWidth) && nresults <= 1 && ttisnumber(arg0) && ttisnumber(args) && ttisnumber(args + 1))
+    if (nparams >= 3 && nresults <= 1 && ttisnumber(arg0) && ttisnumber(args) && ttisnumber(args + 1))
     {
         double a1 = nvalue(arg0);
         double a2 = nvalue(args);
diff --git a/VM/src/lstrlib.cpp b/VM/src/lstrlib.cpp
index b3ea1094..192ea0b5 100644
--- a/VM/src/lstrlib.cpp
+++ b/VM/src/lstrlib.cpp
@@ -8,8 +8,6 @@
 #include <string.h>
 #include <stdio.h>
 
-LUAU_FASTFLAGVARIABLE(LuauTostringFormatSpecifier, false);
-
 // macro to `unsign' a character
 #define uchar(c) ((unsigned char)(c))
 
@@ -1036,9 +1034,6 @@ static int str_format(lua_State* L)
             }
             case '*':
             {
-                if (!FFlag::LuauTostringFormatSpecifier)
-                    luaL_error(L, "invalid option '%%*' to 'format'");
-
                 if (formatItemSize != 1)
                     luaL_error(L, "'%%*' does not take a form");
 
diff --git a/VM/src/lvmexecute.cpp b/VM/src/lvmexecute.cpp
index 7306b055..aa1da8ae 100644
--- a/VM/src/lvmexecute.cpp
+++ b/VM/src/lvmexecute.cpp
@@ -3031,7 +3031,16 @@ static void luau_execute(lua_State* L)
                 TValue* kv = VM_KV(aux & 0xffffff);
                 LUAU_ASSERT(ttisnumber(kv));
 
+#if defined(__aarch64__)
+                // On several ARM chips (Apple M1/M2, Neoverse N1), comparing the result of a floating-point comparison is expensive, and a branch
+                // is much cheaper; on some 32-bit ARM chips (Cortex A53) the performance is about the same so we prefer less branchy variant there
+                if (aux >> 31)
+                    pc += !(ttisnumber(ra) && nvalue(ra) == nvalue(kv)) ? LUAU_INSN_D(insn) : 1;
+                else
+                    pc += (ttisnumber(ra) && nvalue(ra) == nvalue(kv)) ? LUAU_INSN_D(insn) : 1;
+#else
                 pc += int(ttisnumber(ra) && nvalue(ra) == nvalue(kv)) != (aux >> 31) ? LUAU_INSN_D(insn) : 1;
+#endif
                 LUAU_ASSERT(unsigned(pc - cl->l.p->code) < unsigned(cl->l.p->sizecode));
                 VM_NEXT();
             }
diff --git a/tests/AssemblyBuilderX64.test.cpp b/tests/AssemblyBuilderX64.test.cpp
index 3f75ebac..08f241ed 100644
--- a/tests/AssemblyBuilderX64.test.cpp
+++ b/tests/AssemblyBuilderX64.test.cpp
@@ -4,7 +4,6 @@
 
 #include "doctest.h"
 
-#include <functional>
 #include <string.h>
 
 using namespace Luau::CodeGen;
@@ -22,7 +21,7 @@ std::string bytecodeAsArray(const std::vector<uint8_t>& bytecode)
 class AssemblyBuilderX64Fixture
 {
 public:
-    void check(std::function<void(AssemblyBuilderX64& build)> f, std::vector<uint8_t> code, std::vector<uint8_t> data = {})
+    void check(void (*f)(AssemblyBuilderX64& build), std::vector<uint8_t> code, std::vector<uint8_t> data = {})
     {
         AssemblyBuilderX64 build(/* logText= */ false);
 
diff --git a/tests/Compiler.test.cpp b/tests/Compiler.test.cpp
index 0a3c6507..d8520a6e 100644
--- a/tests/Compiler.test.cpp
+++ b/tests/Compiler.test.cpp
@@ -1241,8 +1241,7 @@ TEST_CASE("InterpStringZeroCost")
 {
     ScopedFastFlag sff{"LuauInterpolatedStringBaseSupport", true};
 
-    CHECK_EQ(
-        "\n" + compileFunction0(R"(local _ = `hello, {"world"}!`)"),
+    CHECK_EQ("\n" + compileFunction0(R"(local _ = `hello, {"world"}!`)"),
         R"(
 LOADK R1 K0
 LOADK R3 K1
@@ -1250,16 +1249,14 @@ NAMECALL R1 R1 K2
 CALL R1 2 1
 MOVE R0 R1
 RETURN R0 0
-)"
-    );
+)");
 }
 
 TEST_CASE("InterpStringRegisterCleanup")
 {
     ScopedFastFlag sff{"LuauInterpolatedStringBaseSupport", true};
 
-    CHECK_EQ(
-        "\n" + compileFunction0(R"(
+    CHECK_EQ("\n" + compileFunction0(R"(
             local a, b, c = nil, "um", "uh oh"
             a = `foo{"bar"}`
             print(a)
@@ -1278,8 +1275,7 @@ GETIMPORT R3 6
 MOVE R4 R0
 CALL R3 1 0
 RETURN R0 0
-)"
-    );
+)");
 }
 
 TEST_CASE("ConstantFoldArith")
@@ -2488,8 +2484,6 @@ end
 
 TEST_CASE("DebugLineInfoRepeatUntil")
 {
-    ScopedFastFlag sff("LuauCompileXEQ", true);
-
     CHECK_EQ("\n" + compileFunction0Coverage(R"(
 local f = 0
 repeat
@@ -2834,8 +2828,6 @@ RETURN R0 0
 
 TEST_CASE("AssignmentConflict")
 {
-    ScopedFastFlag sff("LuauCompileOptimalAssignment", true);
-
     // assignments are left to right
     CHECK_EQ("\n" + compileFunction0("local a, b a, b = 1, 2"), R"(
 LOADNIL R0
@@ -3610,8 +3602,6 @@ RETURN R0 1
 
 TEST_CASE("ConstantJumpCompare")
 {
-    ScopedFastFlag sff("LuauCompileXEQ", true);
-
     CHECK_EQ("\n" + compileFunction0(R"(
 local obj = ...
 local b = obj == 1
@@ -6210,8 +6200,6 @@ L4: RETURN R0 -1
 
 TEST_CASE("BuiltinFoldingMultret")
 {
-    ScopedFastFlag sff("LuauCompileXEQ", true);
-
     CHECK_EQ("\n" + compileFunction(R"(
 local NoLanes: Lanes = --[[                             ]] 0b0000000000000000000000000000000
 local OffscreenLane: Lane = --[[                        ]] 0b1000000000000000000000000000000
@@ -6350,8 +6338,6 @@ RETURN R2 1
 
 TEST_CASE("MultipleAssignments")
 {
-    ScopedFastFlag sff("LuauCompileOptimalAssignment", true);
-
     // order of assignments is left to right
     CHECK_EQ("\n" + compileFunction0(R"(
         local a, b
@@ -6574,15 +6560,14 @@ RETURN R0 0
 
 TEST_CASE("BuiltinExtractK")
 {
-    ScopedFastFlag sff("LuauCompileExtractK", true);
-
     // below, K0 refers to a packed f+w constant for bit32.extractk builtin
     // K1 and K2 refer to 1 and 3 and are only used during fallback path
     CHECK_EQ("\n" + compileFunction0(R"(
 local v = ...
 
 return bit32.extract(v, 1, 3)
-)"), R"(
+)"),
+        R"(
 GETVARARGS R0 1
 FASTCALL2K 59 R0 K0 L0
 MOVE R2 R0
diff --git a/tests/Conformance.test.cpp b/tests/Conformance.test.cpp
index f6f5b41f..a7ffb493 100644
--- a/tests/Conformance.test.cpp
+++ b/tests/Conformance.test.cpp
@@ -289,15 +289,12 @@ TEST_CASE("Clear")
 
 TEST_CASE("Strings")
 {
-    ScopedFastFlag sff{"LuauTostringFormatSpecifier", true};
-
     runConformance("strings.lua");
 }
 
 TEST_CASE("StringInterp")
 {
     ScopedFastFlag sffInterpStrings{"LuauInterpolatedStringBaseSupport", true};
-    ScopedFastFlag sffTostringFormat{"LuauTostringFormatSpecifier", true};
 
     runConformance("stringinterp.lua");
 }
@@ -725,13 +722,16 @@ TEST_CASE("NewUserdataOverflow")
     StateRef globalState(luaL_newstate(), lua_close);
     lua_State* L = globalState.get();
 
-    lua_pushcfunction(L, [](lua_State* L1) {
-        // The following userdata request might cause an overflow.
-        lua_newuserdatadtor(L1, SIZE_MAX, [](void* d){});
-        // The overflow might segfault in the following call.
-        lua_getmetatable(L1, -1);
-        return 0;
-    }, nullptr);
+    lua_pushcfunction(
+        L,
+        [](lua_State* L1) {
+            // The following userdata request might cause an overflow.
+            lua_newuserdatadtor(L1, SIZE_MAX, [](void* d) {});
+            // The overflow might segfault in the following call.
+            lua_getmetatable(L1, -1);
+            return 0;
+        },
+        nullptr);
 
     CHECK(lua_pcall(L, 0, 0, 0) == LUA_ERRRUN);
     CHECK(strcmp(lua_tostring(L, -1), "memory allocation error: block too big") == 0);
diff --git a/tests/ConstraintGraphBuilder.test.cpp b/tests/ConstraintGraphBuilder.test.cpp
index 00c3309c..bbe29429 100644
--- a/tests/ConstraintGraphBuilder.test.cpp
+++ b/tests/ConstraintGraphBuilder.test.cpp
@@ -57,13 +57,12 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "nil_primitive")
     auto constraints = collectConstraints(NotNull(cgb.rootScope));
 
     ToStringOptions opts;
-    REQUIRE(5 <= constraints.size());
+    REQUIRE(4 <= constraints.size());
 
     CHECK("*blocked-1* ~ gen () -> (a...)" == toString(*constraints[0], opts));
-    CHECK("*blocked-2* ~ inst *blocked-1*" == toString(*constraints[1], opts));
-    CHECK("() -> (b...) <: *blocked-2*" == toString(*constraints[2], opts));
-    CHECK("b... <: c" == toString(*constraints[3], opts));
-    CHECK("nil <: a..." == toString(*constraints[4], opts));
+    CHECK("call *blocked-1* with { result = *blocked-tp-1* }" == toString(*constraints[1], opts));
+    CHECK("*blocked-tp-1* <: b" == toString(*constraints[2], opts));
+    CHECK("nil <: a..." == toString(*constraints[3], opts));
 }
 
 TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "function_application")
@@ -76,13 +75,12 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "function_application")
     cgb.visit(block);
     auto constraints = collectConstraints(NotNull(cgb.rootScope));
 
-    REQUIRE(4 == constraints.size());
+    REQUIRE(3 == constraints.size());
 
     ToStringOptions opts;
     CHECK("string <: a" == toString(*constraints[0], opts));
-    CHECK("*blocked-1* ~ inst a" == toString(*constraints[1], opts));
-    CHECK("(string) -> (b...) <: *blocked-1*" == toString(*constraints[2], opts));
-    CHECK("b... <: c" == toString(*constraints[3], opts));
+    CHECK("call a with { result = *blocked-tp-1* }" == toString(*constraints[1], opts));
+    CHECK("*blocked-tp-1* <: b" == toString(*constraints[2], opts));
 }
 
 TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "local_function_definition")
@@ -114,13 +112,12 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "recursive_function")
     cgb.visit(block);
     auto constraints = collectConstraints(NotNull(cgb.rootScope));
 
-    REQUIRE(4 == constraints.size());
+    REQUIRE(3 == constraints.size());
 
     ToStringOptions opts;
     CHECK("*blocked-1* ~ gen (a) -> (b...)" == toString(*constraints[0], opts));
-    CHECK("*blocked-2* ~ inst (a) -> (b...)" == toString(*constraints[1], opts));
-    CHECK("(a) -> (c...) <: *blocked-2*" == toString(*constraints[2], opts));
-    CHECK("c... <: b..." == toString(*constraints[3], opts));
+    CHECK("call (a) -> (b...) with { result = *blocked-tp-1* }" == toString(*constraints[1], opts));
+    CHECK("*blocked-tp-1* <: b..." == toString(*constraints[2], opts));
 }
 
 TEST_SUITE_END();
diff --git a/tests/ConstraintSolver.test.cpp b/tests/ConstraintSolver.test.cpp
index e33f6570..2c489733 100644
--- a/tests/ConstraintSolver.test.cpp
+++ b/tests/ConstraintSolver.test.cpp
@@ -28,7 +28,8 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "hello")
     cgb.visit(block);
     NotNull<Scope> rootScope = NotNull(cgb.rootScope);
 
-    ConstraintSolver cs{&arena, rootScope};
+    NullModuleResolver resolver;
+    ConstraintSolver cs{&arena, rootScope, "MainModule", NotNull(&resolver), {}};
 
     cs.run();
 
@@ -48,7 +49,8 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "generic_function")
     cgb.visit(block);
     NotNull<Scope> rootScope = NotNull(cgb.rootScope);
 
-    ConstraintSolver cs{&arena, rootScope};
+    NullModuleResolver resolver;
+    ConstraintSolver cs{&arena, rootScope, "MainModule", NotNull(&resolver), {}};
 
     cs.run();
 
@@ -57,7 +59,6 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "generic_function")
     CHECK("<a>(a) -> a" == toString(idType));
 }
 
-#if 1
 TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "proper_let_generalization")
 {
     AstStatBlock* block = parse(R"(
@@ -77,7 +78,8 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "proper_let_generalization")
 
     ToStringOptions opts;
 
-    ConstraintSolver cs{&arena, rootScope};
+    NullModuleResolver resolver;
+    ConstraintSolver cs{&arena, rootScope, "MainModule", NotNull(&resolver), {}};
 
     cs.run();
 
@@ -85,6 +87,5 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "proper_let_generalization")
 
     CHECK("<a>(a) -> number" == toString(idType, opts));
 }
-#endif
 
 TEST_SUITE_END();
diff --git a/tests/Fixture.cpp b/tests/Fixture.cpp
index 4051f851..476b7a2a 100644
--- a/tests/Fixture.cpp
+++ b/tests/Fixture.cpp
@@ -2,6 +2,8 @@
 #include "Fixture.h"
 
 #include "Luau/AstQuery.h"
+#include "Luau/ModuleResolver.h"
+#include "Luau/NotNull.h"
 #include "Luau/Parser.h"
 #include "Luau/TypeVar.h"
 #include "Luau/TypeAttach.h"
@@ -444,10 +446,11 @@ BuiltinsFixture::BuiltinsFixture(bool freeze, bool prepareAutocomplete)
 ConstraintGraphBuilderFixture::ConstraintGraphBuilderFixture()
     : Fixture()
     , mainModule(new Module)
-    , cgb(mainModuleName, mainModule, &arena, NotNull(&ice), frontend.getGlobalScope())
+    , cgb(mainModuleName, mainModule, &arena, NotNull(&moduleResolver), NotNull(&ice), frontend.getGlobalScope())
     , forceTheFlag{"DebugLuauDeferredConstraintResolution", true}
 {
     BlockedTypeVar::nextIndex = 0;
+    BlockedTypePack::nextIndex = 0;
 }
 
 ModuleName fromString(std::string_view name)
diff --git a/tests/Fixture.h b/tests/Fixture.h
index e82ebf00..8923b208 100644
--- a/tests/Fixture.h
+++ b/tests/Fixture.h
@@ -132,6 +132,7 @@ struct Fixture
 
     TestFileResolver fileResolver;
     TestConfigResolver configResolver;
+    NullModuleResolver moduleResolver;
     std::unique_ptr<SourceModule> sourceModule;
     Frontend frontend;
     InternalErrorReporter ice;
@@ -213,7 +214,7 @@ Nth nth(int nth = 1)
 struct FindNthOccurenceOf : public AstVisitor
 {
     Nth requestedNth;
-    size_t currentOccurrence = 0;
+    int currentOccurrence = 0;
     AstNode* theNode = nullptr;
 
     FindNthOccurenceOf(Nth nth);
@@ -244,7 +245,7 @@ struct FindNthOccurenceOf : public AstVisitor
  * 2. Luau::query<AstExprBinary>(Luau::query<AstStatFunction>(block))
  * 3. Luau::query<AstExprBinary>(block, {nth<AstExprBinary>(2)})
  */
-template<typename T, size_t N = 1>
+template<typename T, int N = 1>
 T* query(AstNode* node, const std::vector<Nth>& nths = {nth<T>(N)})
 {
     static_assert(std::is_base_of_v<AstNode, T>, "T must be a derived class of AstNode");
diff --git a/tests/JsonEmitter.test.cpp b/tests/JsonEmitter.test.cpp
index ebe83209..ff9a5955 100644
--- a/tests/JsonEmitter.test.cpp
+++ b/tests/JsonEmitter.test.cpp
@@ -94,7 +94,7 @@ TEST_CASE("write_optional")
     write(emitter, std::optional<bool>{true});
     emitter.writeComma();
     write(emitter, std::nullopt);
-    
+
     CHECK(emitter.str() == "true,null");
 }
 
diff --git a/tests/Linter.test.cpp b/tests/Linter.test.cpp
index a7d09e8f..b560c89e 100644
--- a/tests/Linter.test.cpp
+++ b/tests/Linter.test.cpp
@@ -1181,7 +1181,7 @@ s:match("[]")
 nons:match("[]")
 )~");
 
-    CHECK_EQ(result.warnings.size(), 2);
+    REQUIRE_EQ(result.warnings.size(), 2);
     CHECK_EQ(result.warnings[0].text, "Invalid match pattern: expected ] at the end of the string to close a set");
     CHECK_EQ(result.warnings[0].location.begin.line, 3);
     CHECK_EQ(result.warnings[1].text, "Invalid match pattern: expected ] at the end of the string to close a set");
@@ -1746,6 +1746,7 @@ local _ = not a == b
 local _ = not a ~= b
 local _ = not a <= b
 local _ = a <= b == 0
+local _ = a <= b <= 0
 
 local _ = not a == not b -- weird but ok
 
@@ -1760,11 +1761,12 @@ local _ = (a <= b) == 0
 local _ = a <= (b == 0)
 )");
 
-    REQUIRE_EQ(result.warnings.size(), 4);
-    CHECK_EQ(result.warnings[0].text, "not X == Y is equivalent to (not X) == Y; consider using X ~= Y, or wrap one of the expressions in parentheses to silence");
-    CHECK_EQ(result.warnings[1].text, "not X ~= Y is equivalent to (not X) ~= Y; consider using X == Y, or wrap one of the expressions in parentheses to silence");
-    CHECK_EQ(result.warnings[2].text, "not X <= Y is equivalent to (not X) <= Y; wrap one of the expressions in parentheses to silence");
-    CHECK_EQ(result.warnings[3].text, "X <= Y == Z is equivalent to (X <= Y) == Z; wrap one of the expressions in parentheses to silence");
+    REQUIRE_EQ(result.warnings.size(), 5);
+    CHECK_EQ(result.warnings[0].text, "not X == Y is equivalent to (not X) == Y; consider using X ~= Y, or add parentheses to silence");
+    CHECK_EQ(result.warnings[1].text, "not X ~= Y is equivalent to (not X) ~= Y; consider using X == Y, or add parentheses to silence");
+    CHECK_EQ(result.warnings[2].text, "not X <= Y is equivalent to (not X) <= Y; add parentheses to silence");
+    CHECK_EQ(result.warnings[3].text, "X <= Y == Z is equivalent to (X <= Y) == Z; add parentheses to silence");
+    CHECK_EQ(result.warnings[4].text, "X <= Y <= Z is equivalent to (X <= Y) <= Z; did you mean X <= Y and Y <= Z?");
 }
 
 TEST_SUITE_END();
diff --git a/tests/Parser.test.cpp b/tests/Parser.test.cpp
index 2dd47708..44a6b4ac 100644
--- a/tests/Parser.test.cpp
+++ b/tests/Parser.test.cpp
@@ -943,8 +943,7 @@ TEST_CASE_FIXTURE(Fixture, "parse_interpolated_string_without_end_brace")
 {
     ScopedFastFlag sff{"LuauInterpolatedStringBaseSupport", true};
 
-    auto columnOfEndBraceError = [this](const char* code)
-    {
+    auto columnOfEndBraceError = [this](const char* code) {
         try
         {
             parse(code);
@@ -1737,6 +1736,48 @@ TEST_CASE_FIXTURE(Fixture, "parse_error_type_annotation")
     matchParseError("local a : 2 = 2", "Expected type, got '2'");
 }
 
+TEST_CASE_FIXTURE(Fixture, "parse_error_missing_type_annotation")
+{
+    ScopedFastFlag LuauTypeAnnotationLocationChange{"LuauTypeAnnotationLocationChange", true};
+
+    {
+        ParseResult result = tryParse("local x:");
+        CHECK(result.errors.size() == 1);
+        Position begin = result.errors[0].getLocation().begin;
+        Position end = result.errors[0].getLocation().end;
+        CHECK(begin.line == end.line);
+        int width = end.column - begin.column;
+        CHECK(width == 0);
+        CHECK(result.errors[0].getMessage() == "Expected type, got <eof>");
+    }
+
+    {
+        ParseResult result = tryParse(R"(
+local x:=42
+    )");
+        CHECK(result.errors.size() == 1);
+        Position begin = result.errors[0].getLocation().begin;
+        Position end = result.errors[0].getLocation().end;
+        CHECK(begin.line == end.line);
+        int width = end.column - begin.column;
+        CHECK(width == 1); // Length of `=`
+        CHECK(result.errors[0].getMessage() == "Expected type, got '='");
+    }
+
+    {
+        ParseResult result = tryParse(R"(
+function func():end
+    )");
+        CHECK(result.errors.size() == 1);
+        Position begin = result.errors[0].getLocation().begin;
+        Position end = result.errors[0].getLocation().end;
+        CHECK(begin.line == end.line);
+        int width = end.column - begin.column;
+        CHECK(width == 3); // Length of `end`
+        CHECK(result.errors[0].getMessage() == "Expected type, got 'end'");
+    }
+}
+
 TEST_CASE_FIXTURE(Fixture, "parse_declarations")
 {
     AstStatBlock* stat = parseEx(R"(
diff --git a/tests/TypeInfer.anyerror.test.cpp b/tests/TypeInfer.anyerror.test.cpp
index f4766104..8c6f2e4f 100644
--- a/tests/TypeInfer.anyerror.test.cpp
+++ b/tests/TypeInfer.anyerror.test.cpp
@@ -346,4 +346,17 @@ TEST_CASE_FIXTURE(Fixture, "prop_access_on_any_with_other_options")
     LUAU_REQUIRE_NO_ERRORS(result);
 }
 
+TEST_CASE_FIXTURE(BuiltinsFixture, "union_of_types_regression_test")
+{
+    ScopedFastFlag LuauUnionOfTypesFollow{"LuauUnionOfTypesFollow", true};
+
+    CheckResult result = check(R"(
+--!strict
+local stat
+stat = stat and tonumber(stat) or stat
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
 TEST_SUITE_END();
diff --git a/tests/TypeInfer.builtins.test.cpp b/tests/TypeInfer.builtins.test.cpp
index 12fb4aa2..07a04363 100644
--- a/tests/TypeInfer.builtins.test.cpp
+++ b/tests/TypeInfer.builtins.test.cpp
@@ -1061,7 +1061,6 @@ end
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types")
 {
-    ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
     CheckResult result = check(R"END(
         local a, b, c = string.gmatch("This is a string", "(.()(%a+))")()
     )END");
@@ -1075,7 +1074,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types")
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types2")
 {
-    ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
     CheckResult result = check(R"END(
         local a, b, c = ("This is a string"):gmatch("(.()(%a+))")()
     )END");
@@ -1089,7 +1087,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types2")
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_default_capture")
 {
-    ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
     CheckResult result = check(R"END(
         local a, b, c, d = string.gmatch("T(his)() is a string", ".")()
     )END");
@@ -1107,7 +1104,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_default_capture")
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_balanced_escaped_parens")
 {
-    ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
     CheckResult result = check(R"END(
         local a, b, c, d = string.gmatch("T(his) is a string", "((.)%b()())")()
     )END");
@@ -1127,7 +1123,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_balanced_escaped_parens
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_parens_in_sets_are_ignored")
 {
-    ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
     CheckResult result = check(R"END(
         local a, b, c = string.gmatch("T(his)() is a string", "(T[()])()")()
     )END");
@@ -1146,7 +1141,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_parens_in_sets_are_igno
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_set_containing_lbracket")
 {
-    ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
     CheckResult result = check(R"END(
         local a, b = string.gmatch("[[[", "()([[])")()
     )END");
@@ -1196,7 +1190,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_invalid_pattern_fallbac
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "match_capture_types")
 {
-    ScopedFastFlag sffs{"LuauDeduceFindMatchReturnTypes", true};
     CheckResult result = check(R"END(
         local a, b, c = string.match("This is a string", "(.()(%a+))")
     )END");
@@ -1210,7 +1203,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "match_capture_types")
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "match_capture_types2")
 {
-    ScopedFastFlag sffs{"LuauDeduceFindMatchReturnTypes", true};
     CheckResult result = check(R"END(
         local a, b, c = string.match("This is a string", "(.()(%a+))", "this should be a number")
     )END");
@@ -1229,7 +1221,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "match_capture_types2")
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "find_capture_types")
 {
-    ScopedFastFlag sffs{"LuauDeduceFindMatchReturnTypes", true};
     CheckResult result = check(R"END(
         local d, e, a, b, c = string.find("This is a string", "(.()(%a+))")
     )END");
@@ -1245,7 +1236,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "find_capture_types")
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "find_capture_types2")
 {
-    ScopedFastFlag sffs{"LuauDeduceFindMatchReturnTypes", true};
     CheckResult result = check(R"END(
         local d, e, a, b, c = string.find("This is a string", "(.()(%a+))", "this should be a number")
     )END");
@@ -1266,7 +1256,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "find_capture_types2")
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "find_capture_types3")
 {
-    ScopedFastFlag sffs{"LuauDeduceFindMatchReturnTypes", true};
     CheckResult result = check(R"END(
         local d, e, a, b, c = string.find("This is a string", "(.()(%a+))", 1, "this should be a bool")
     )END");
@@ -1287,7 +1276,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "find_capture_types3")
 
 TEST_CASE_FIXTURE(BuiltinsFixture, "find_capture_types3")
 {
-    ScopedFastFlag sffs{"LuauDeduceFindMatchReturnTypes", true};
     CheckResult result = check(R"END(
         local d, e, a, b = string.find("This is a string", "(.()(%a+))", 1, true)
     )END");
diff --git a/tests/TypeInfer.definitions.test.cpp b/tests/TypeInfer.definitions.test.cpp
index fd6fb83f..9fe0c6aa 100644
--- a/tests/TypeInfer.definitions.test.cpp
+++ b/tests/TypeInfer.definitions.test.cpp
@@ -336,4 +336,30 @@ local s : Cls = GetCls()
     LUAU_REQUIRE_NO_ERRORS(result);
 }
 
+TEST_CASE_FIXTURE(Fixture, "class_definition_overload_metamethods")
+{
+    loadDefinition(R"(
+        declare class Vector3
+        end
+
+        declare class CFrame
+            function __mul(self, other: CFrame): CFrame
+            function __mul(self, other: Vector3): Vector3
+        end
+
+        declare function newVector3(): Vector3
+        declare function newCFrame(): CFrame
+    )");
+
+    CheckResult result = check(R"(
+        local base = newCFrame()
+        local shouldBeCFrame = base * newCFrame()
+        local shouldBeVector = base * newVector3()
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+    CHECK_EQ(toString(requireType("shouldBeCFrame")), "CFrame");
+    CHECK_EQ(toString(requireType("shouldBeVector")), "Vector3");
+}
+
 TEST_SUITE_END();
diff --git a/tests/TypeInfer.functions.test.cpp b/tests/TypeInfer.functions.test.cpp
index 5cc759d6..3a6f4491 100644
--- a/tests/TypeInfer.functions.test.cpp
+++ b/tests/TypeInfer.functions.test.cpp
@@ -133,6 +133,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "vararg_function_is_quantified")
     TableTypeVar* ttv = getMutable<TableTypeVar>(*r);
     REQUIRE(ttv);
 
+    REQUIRE(ttv->props.count("f"));
     TypeId k = ttv->props["f"].type;
     REQUIRE(k);
 
diff --git a/tests/TypeInfer.loops.test.cpp b/tests/TypeInfer.loops.test.cpp
index 9b10092c..85249ecd 100644
--- a/tests/TypeInfer.loops.test.cpp
+++ b/tests/TypeInfer.loops.test.cpp
@@ -14,6 +14,7 @@
 using namespace Luau;
 
 LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
+LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution)
 
 TEST_SUITE_BEGIN("TypeInferLoops");
 
@@ -109,6 +110,18 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_with_just_one_iterator_is_ok")
     LUAU_REQUIRE_NO_ERRORS(result);
 }
 
+TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_zero_iterators_dcr")
+{
+    ScopedFastFlag sff{"DebugLuauDeferredConstraintResolution", true};
+
+    CheckResult result = check(R"(
+        function no_iter() end
+        for key in no_iter() do end
+    )");
+
+    LUAU_REQUIRE_ERROR_COUNT(1, result);
+}
+
 TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_with_a_custom_iterator_should_type_check")
 {
     CheckResult result = check(R"(
@@ -141,7 +154,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_error")
         end
     )");
 
-    CHECK_EQ(2, result.errors.size());
+    LUAU_REQUIRE_ERROR_COUNT(2, result);
 
     TypeId p = requireType("p");
     if (FFlag::LuauSpecialTypesAsterisked)
@@ -232,6 +245,30 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_error_on_iterator_requiring_args
     CHECK_EQ(0, acm->actual);
 }
 
+TEST_CASE_FIXTURE(Fixture, "for_in_loop_with_incompatible_args_to_iterator")
+{
+    CheckResult result = check(R"(
+        function my_iter(state: string, index: number)
+            return state, index
+        end
+
+        local my_state = {}
+        local first_index = "first"
+
+        -- Type errors here.  my_state and first_index cannot be passed to my_iter
+        for a, b in my_iter, my_state, first_index do
+        end
+    )");
+
+    LUAU_REQUIRE_ERROR_COUNT(2, result);
+
+    CHECK(get<TypeMismatch>(result.errors[1]));
+    CHECK(Location{{9, 29}, {9, 37}} == result.errors[0].location);
+
+    CHECK(get<TypeMismatch>(result.errors[1]));
+    CHECK(Location{{9, 39}, {9, 50}} == result.errors[1].location);
+}
+
 TEST_CASE_FIXTURE(Fixture, "for_in_loop_with_custom_iterator")
 {
     CheckResult result = check(R"(
@@ -503,7 +540,7 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_basic")
         end
     )");
 
-    LUAU_REQUIRE_ERROR_COUNT(0, result);
+    LUAU_REQUIRE_NO_ERRORS(result);
     CHECK_EQ(*typeChecker.numberType, *requireType("key"));
 }
 
diff --git a/tests/TypeInfer.modules.test.cpp b/tests/TypeInfer.modules.test.cpp
index b5f2296c..ede84f4a 100644
--- a/tests/TypeInfer.modules.test.cpp
+++ b/tests/TypeInfer.modules.test.cpp
@@ -16,6 +16,35 @@ LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
 
 TEST_SUITE_BEGIN("TypeInferModules");
 
+TEST_CASE_FIXTURE(BuiltinsFixture, "dcr_require_basic")
+{
+    fileResolver.source["game/A"] = R"(
+        --!strict
+        return {
+            a = 1,
+        }
+    )";
+
+    fileResolver.source["game/B"] = R"(
+        --!strict
+        local A = require(game.A)
+
+        local b = A.a
+    )";
+
+    CheckResult aResult = frontend.check("game/A");
+    LUAU_REQUIRE_NO_ERRORS(aResult);
+
+    CheckResult bResult = frontend.check("game/B");
+    LUAU_REQUIRE_NO_ERRORS(bResult);
+
+    ModulePtr b = frontend.moduleResolver.modules["game/B"];
+    REQUIRE(b != nullptr);
+    std::optional<TypeId> bType = requireType(b, "b");
+    REQUIRE(bType);
+    CHECK(toString(*bType) == "number");
+}
+
 TEST_CASE_FIXTURE(BuiltinsFixture, "require")
 {
     fileResolver.source["game/A"] = R"(
diff --git a/tests/TypeInfer.primitives.test.cpp b/tests/TypeInfer.primitives.test.cpp
index a06fd749..5a6fb0e4 100644
--- a/tests/TypeInfer.primitives.test.cpp
+++ b/tests/TypeInfer.primitives.test.cpp
@@ -11,7 +11,6 @@
 
 #include "doctest.h"
 
-LUAU_FASTFLAG(LuauDeduceFindMatchReturnTypes)
 LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
 
 using namespace Luau;
@@ -61,8 +60,8 @@ TEST_CASE_FIXTURE(Fixture, "string_method")
     CheckResult result = check(R"(
         local p = ("tacos"):len()
     )");
-    CHECK_EQ(0, result.errors.size());
 
+    LUAU_REQUIRE_NO_ERRORS(result);
     CHECK_EQ(*requireType("p"), *typeChecker.numberType);
 }
 
@@ -73,8 +72,8 @@ TEST_CASE_FIXTURE(Fixture, "string_function_indirect")
         local l = s.lower
         local p = l(s)
     )");
-    CHECK_EQ(0, result.errors.size());
 
+    LUAU_REQUIRE_NO_ERRORS(result);
     CHECK_EQ(*requireType("p"), *typeChecker.stringType);
 }
 
@@ -84,12 +83,9 @@ TEST_CASE_FIXTURE(Fixture, "string_function_other")
         local s:string
         local p = s:match("foo")
     )");
-    CHECK_EQ(0, result.errors.size());
 
-    if (FFlag::LuauDeduceFindMatchReturnTypes)
-        CHECK_EQ(toString(requireType("p")), "string");
-    else
-        CHECK_EQ(toString(requireType("p")), "string?");
+    LUAU_REQUIRE_NO_ERRORS(result);
+    CHECK_EQ(toString(requireType("p")), "string");
 }
 
 TEST_CASE_FIXTURE(Fixture, "CheckMethodsOfNumber")
diff --git a/tests/TypeInfer.provisional.test.cpp b/tests/TypeInfer.provisional.test.cpp
index c8fc7f2d..472d0ed5 100644
--- a/tests/TypeInfer.provisional.test.cpp
+++ b/tests/TypeInfer.provisional.test.cpp
@@ -62,7 +62,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "xpcall_returns_what_f_returns")
         local a:boolean,b:number,c:string=xpcall(function(): (number,string)return 1,'foo'end,function(): (string,number)return'foo',1 end)
     )";
 
-    CHECK_EQ(expected, decorateWithTypes(code));
+    CheckResult result = check(code);
+
+    CHECK("boolean" == toString(requireType("a")));
+    CHECK("number" == toString(requireType("b")));
+    CHECK("string" == toString(requireType("c")));
+
+    CHECK(expected == decorateWithTypes(code));
 }
 
 // We had a bug where if you have two type packs that looks like:
@@ -609,4 +615,16 @@ TEST_CASE_FIXTURE(Fixture, "free_options_cannot_be_unified_together")
     CHECK("b?" == toString(option2, opts)); // This should not hold.
 }
 
+TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_zero_iterators")
+{
+    ScopedFastFlag sff{"DebugLuauDeferredConstraintResolution", false};
+
+    CheckResult result = check(R"(
+        function no_iter() end
+        for key in no_iter() do end -- This should not be ok
+    )");
+
+    LUAU_REQUIRE_NO_ERRORS(result);
+}
+
 TEST_SUITE_END();
diff --git a/tests/TypeInfer.tables.test.cpp b/tests/TypeInfer.tables.test.cpp
index 95b85c48..97c3da4f 100644
--- a/tests/TypeInfer.tables.test.cpp
+++ b/tests/TypeInfer.tables.test.cpp
@@ -2994,8 +2994,6 @@ TEST_CASE_FIXTURE(Fixture, "expected_indexer_value_type_extra_2")
 
 TEST_CASE_FIXTURE(Fixture, "expected_indexer_from_table_union")
 {
-    ScopedFastFlag luauExpectedTableUnionIndexerType{"LuauExpectedTableUnionIndexerType", true};
-
     LUAU_REQUIRE_NO_ERRORS(check(R"(local a: {[string]: {number | string}} = {a = {2, 's'}})"));
     LUAU_REQUIRE_NO_ERRORS(check(R"(local a: {[string]: {number | string}}? = {a = {2, 's'}})"));
     LUAU_REQUIRE_NO_ERRORS(check(R"(local a: {[string]: {[string]: {string?}}?} = {["a"] = {["b"] = {"a", "b"}}})"));
diff --git a/tests/conformance/basic.lua b/tests/conformance/basic.lua
index d9274751..9c19da59 100644
--- a/tests/conformance/basic.lua
+++ b/tests/conformance/basic.lua
@@ -111,6 +111,11 @@ assert((function() local a = nil a = a and 2 return a end)() == nil)
 assert((function() local a = 1 a = a or 2 return a end)() == 1)
 assert((function() local a = nil a = a or 2 return a end)() == 2)
 
+assert((function() local a a = 1 local b = 2 b = a and b return b end)() == 2)
+assert((function() local a a = nil local b = 2 b = a and b return b end)() == nil)
+assert((function() local a a = 1 local b = 2 b = a or b return b end)() == 1)
+assert((function() local a a = nil local b = 2 b = a or b return b end)() == 2)
+
 -- binary arithmetics coerces strings to numbers (sadly)
 assert(1 + "2" == 3)
 assert(2 * "0xa" == 20)
diff --git a/tests/conformance/errors.lua b/tests/conformance/errors.lua
index b69d437b..529e9b0c 100644
--- a/tests/conformance/errors.lua
+++ b/tests/conformance/errors.lua
@@ -369,21 +369,31 @@ assert(not a and b:match('[^ ]+') == "short:1:")
 local a,b = loadstring("nope", "=" .. string.rep("thisisaverylongstringitssolongthatitwontfitintotheinternalbufferprovidedtovariousdebugfacilities", 10))
 assert(not a and b:match('[^ ]+') == "thisisaverylongstringitssolongthatitwontfitintotheinternalbufferprovidedtovariousdebugfacilitiesthisisaverylongstringitssolongthatitwontfitintotheinternalbufferprovidedtovariousdebugfacilitiesthisisaverylongstringitssolongthatitwontfitintotheinternalbuffe:1:")
 
--- arith errors
 function ecall(fn, ...)
   local ok, err = pcall(fn, ...)
   assert(not ok)
-  return err:sub(err:find(": ") + 2, #err)
+  return err:sub((err:find(": ") or -1) + 2, #err)
 end
 
+-- arith errors
 assert(ecall(function() return nil + 5 end) == "attempt to perform arithmetic (add) on nil and number")
 assert(ecall(function() return "a" + "b" end) == "attempt to perform arithmetic (add) on string")
 assert(ecall(function() return 1 > nil end) == "attempt to compare nil < number") -- note reversed order (by design)
 assert(ecall(function() return "a" <= 5 end) == "attempt to compare string <= number")
 
+-- table errors
 assert(ecall(function() local t = {} t[nil] = 2 end) == "table index is nil")
 assert(ecall(function() local t = {} t[0/0] = 2 end) == "table index is NaN")
 
+assert(ecall(function() local t = {} rawset(t, nil, 2) end) == "table index is nil")
+assert(ecall(function() local t = {} rawset(t, 0/0, 2) end) == "table index is NaN")
+
+assert(ecall(function() local t = {} t[nil] = nil end) == "table index is nil")
+assert(ecall(function() local t = {} t[0/0] = nil end) == "table index is NaN")
+
+assert(ecall(function() local t = {} rawset(t, nil, nil) end) == "table index is nil")
+assert(ecall(function() local t = {} rawset(t, 0/0, nil) end) == "table index is NaN")
+
 -- for loop type errors
 assert(ecall(function() for i='a',2 do end end) == "invalid 'for' initial value (number expected, got string)")
 assert(ecall(function() for i=1,'a' do end end) == "invalid 'for' limit (number expected, got string)")
diff --git a/tools/faillist.txt b/tools/faillist.txt
index 54e7ac05..3de9db76 100644
--- a/tools/faillist.txt
+++ b/tools/faillist.txt
@@ -1,10 +1,8 @@
 AnnotationTests.builtin_types_are_not_exported
-AnnotationTests.cannot_use_nonexported_type
-AnnotationTests.cloned_interface_maintains_pointers_between_definitions
 AnnotationTests.duplicate_type_param_name
 AnnotationTests.for_loop_counter_annotation_is_checked
 AnnotationTests.generic_aliases_are_cloned_properly
-AnnotationTests.interface_types_belong_to_interface_arena
+AnnotationTests.instantiation_clone_has_to_follow
 AnnotationTests.luau_ice_triggers_an_ice
 AnnotationTests.luau_ice_triggers_an_ice_exception_with_flag
 AnnotationTests.luau_ice_triggers_an_ice_exception_with_flag_handler
@@ -26,6 +24,7 @@ AutocompleteTest.autocomplete_first_function_arg_expected_type
 AutocompleteTest.autocomplete_for_in_middle_keywords
 AutocompleteTest.autocomplete_for_middle_keywords
 AutocompleteTest.autocomplete_if_middle_keywords
+AutocompleteTest.autocomplete_interpolated_string
 AutocompleteTest.autocomplete_on_string_singletons
 AutocompleteTest.autocomplete_oop_implicit_self
 AutocompleteTest.autocomplete_repeat_middle_keyword
@@ -56,14 +55,12 @@ AutocompleteTest.global_functions_are_not_scoped_lexically
 AutocompleteTest.globals_are_order_independent
 AutocompleteTest.if_then_else_elseif_completions
 AutocompleteTest.keyword_methods
-AutocompleteTest.keyword_types
 AutocompleteTest.library_non_self_calls_are_fine
 AutocompleteTest.library_self_calls_are_invalid
 AutocompleteTest.local_function
 AutocompleteTest.local_function_params
 AutocompleteTest.local_functions_fall_out_of_scope
 AutocompleteTest.method_call_inside_function_body
-AutocompleteTest.module_type_members
 AutocompleteTest.nested_member_completions
 AutocompleteTest.nested_recursive_function
 AutocompleteTest.no_function_name_suggestions
@@ -78,7 +75,6 @@ AutocompleteTest.return_types
 AutocompleteTest.sometimes_the_metatable_is_an_error
 AutocompleteTest.source_module_preservation_and_invalidation
 AutocompleteTest.statement_between_two_statements
-AutocompleteTest.stop_at_first_stat_when_recommending_keywords
 AutocompleteTest.string_prim_non_self_calls_are_avoided
 AutocompleteTest.string_prim_self_calls_are_fine
 AutocompleteTest.suggest_external_module_type
@@ -155,6 +151,7 @@ BuiltinTests.string_format_tostring_specifier
 BuiltinTests.string_format_tostring_specifier_type_constraint
 BuiltinTests.string_format_use_correct_argument
 BuiltinTests.string_format_use_correct_argument2
+BuiltinTests.string_format_use_correct_argument3
 BuiltinTests.string_lib_self_noself
 BuiltinTests.table_concat_returns_string
 BuiltinTests.table_dot_remove_optionally_returns_generic
@@ -168,31 +165,21 @@ BuiltinTests.tonumber_returns_optional_number_type
 BuiltinTests.tonumber_returns_optional_number_type2
 DefinitionTests.declaring_generic_functions
 DefinitionTests.definition_file_classes
-DefinitionTests.definition_file_loading
-DefinitionTests.definitions_documentation_symbols
-DefinitionTests.documentation_symbols_dont_attach_to_persistent_types
-DefinitionTests.single_class_type_identity_in_global_types
 FrontendTest.ast_node_at_position
 FrontendTest.automatically_check_dependent_scripts
-FrontendTest.check_without_builtin_next
 FrontendTest.dont_reparse_clean_file_when_linting
 FrontendTest.environments
 FrontendTest.imported_table_modification_2
 FrontendTest.it_should_be_safe_to_stringify_errors_when_full_type_graph_is_discarded
-FrontendTest.no_use_after_free_with_type_fun_instantiation
 FrontendTest.nocheck_cycle_used_by_checked
-FrontendTest.nocheck_modules_are_typed
 FrontendTest.produce_errors_for_unchanged_file_with_a_syntax_error
 FrontendTest.recheck_if_dependent_script_is_dirty
 FrontendTest.reexport_cyclic_type
-FrontendTest.reexport_type_alias
-FrontendTest.report_require_to_nonexistent_file
 FrontendTest.report_syntax_error_in_required_file
 FrontendTest.trace_requires_in_nonstrict_mode
 GenericsTests.apply_type_function_nested_generics1
 GenericsTests.apply_type_function_nested_generics2
 GenericsTests.better_mismatch_error_messages
-GenericsTests.bound_tables_do_not_clone_original_fields
 GenericsTests.calling_self_generic_methods
 GenericsTests.check_generic_typepack_function
 GenericsTests.check_mutual_generic_functions
@@ -208,7 +195,6 @@ GenericsTests.factories_of_generics
 GenericsTests.generic_argument_count_too_few
 GenericsTests.generic_argument_count_too_many
 GenericsTests.generic_factories
-GenericsTests.generic_functions_dont_cache_type_parameters
 GenericsTests.generic_functions_in_types
 GenericsTests.generic_functions_should_be_memory_safe
 GenericsTests.generic_table_method
@@ -245,7 +231,6 @@ IntersectionTypes.no_stack_overflow_from_flattenintersection
 IntersectionTypes.overload_is_not_a_function
 IntersectionTypes.select_correct_union_fn
 IntersectionTypes.should_still_pick_an_overload_whose_arguments_are_unions
-IntersectionTypes.table_intersection_write
 IntersectionTypes.table_intersection_write_sealed
 IntersectionTypes.table_intersection_write_sealed_indirect
 IntersectionTypes.table_write_sealed_indirect
@@ -255,7 +240,6 @@ Linter.TableOperations
 ModuleTests.clone_self_property
 ModuleTests.deepClone_cyclic_table
 ModuleTests.do_not_clone_reexports
-ModuleTests.do_not_clone_types_of_reexported_values
 NonstrictModeTests.delay_function_does_not_require_its_argument_to_return_anything
 NonstrictModeTests.for_in_iterator_variables_are_any
 NonstrictModeTests.function_parameters_are_any
@@ -319,6 +303,7 @@ ProvisionalTests.typeguard_inference_incomplete
 ProvisionalTests.weird_fail_to_unify_type_pack
 ProvisionalTests.weirditer_should_not_loop_forever
 ProvisionalTests.while_body_are_also_refined
+ProvisionalTests.xpcall_returns_what_f_returns
 RefinementTest.and_constraint
 RefinementTest.and_or_peephole_refinement
 RefinementTest.apply_refinements_on_astexprindexexpr_whose_subscript_expr_is_constant_string
@@ -358,6 +343,7 @@ RefinementTest.not_and_constraint
 RefinementTest.not_t_or_some_prop_of_t
 RefinementTest.or_predicate_with_truthy_predicates
 RefinementTest.parenthesized_expressions_are_followed_through
+RefinementTest.refine_a_property_not_to_be_nil_through_an_intersection_table
 RefinementTest.refine_the_correct_types_opposite_of_when_a_is_not_number_or_string
 RefinementTest.refine_unknowns
 RefinementTest.string_not_equal_to_string_or_nil
@@ -394,7 +380,6 @@ TableTests.augment_table
 TableTests.builtin_table_names
 TableTests.call_method
 TableTests.cannot_augment_sealed_table
-TableTests.cannot_call_tables
 TableTests.cannot_change_type_of_unsealed_table_prop
 TableTests.casting_sealed_tables_with_props_into_table_with_indexer
 TableTests.casting_tables_with_props_into_table_with_indexer3
@@ -409,7 +394,6 @@ TableTests.defining_a_self_method_for_a_builtin_sealed_table_must_fail
 TableTests.defining_a_self_method_for_a_local_sealed_table_must_fail
 TableTests.dont_crash_when_setmetatable_does_not_produce_a_metatabletypevar
 TableTests.dont_hang_when_trying_to_look_up_in_cyclic_metatable_index
-TableTests.dont_invalidate_the_properties_iterator_of_free_table_when_rolled_back
 TableTests.dont_leak_free_table_props
 TableTests.dont_quantify_table_that_belongs_to_outer_scope
 TableTests.dont_suggest_exact_match_keys
@@ -448,6 +432,7 @@ TableTests.length_operator_intersection
 TableTests.length_operator_non_table_union
 TableTests.length_operator_union
 TableTests.length_operator_union_errors
+TableTests.less_exponential_blowup_please
 TableTests.meta_add
 TableTests.meta_add_both_ways
 TableTests.meta_add_inferred
@@ -470,7 +455,6 @@ TableTests.quantify_even_that_table_was_never_exported_at_all
 TableTests.quantify_metatables_of_metatables_of_table
 TableTests.quantifying_a_bound_var_works
 TableTests.reasonable_error_when_adding_a_nonexistent_property_to_an_array_like_table
-TableTests.recursive_metatable_type_call
 TableTests.result_is_always_any_if_lhs_is_any
 TableTests.result_is_bool_for_equality_operators_if_lhs_is_any
 TableTests.right_table_missing_key
@@ -480,7 +464,6 @@ TableTests.scalar_is_not_a_subtype_of_a_compatible_polymorphic_shape_type
 TableTests.shared_selfs
 TableTests.shared_selfs_from_free_param
 TableTests.shared_selfs_through_metatables
-TableTests.table_function_check_use_after_free
 TableTests.table_indexing_error_location
 TableTests.table_insert_should_cope_with_optional_properties_in_nonstrict
 TableTests.table_insert_should_cope_with_optional_properties_in_strict
@@ -525,13 +508,10 @@ TryUnifyTests.result_of_failed_typepack_unification_is_constrained
 TryUnifyTests.typepack_unification_should_trim_free_tails
 TryUnifyTests.variadics_should_use_reversed_properly
 TypeAliases.cli_38393_recursive_intersection_oom
-TypeAliases.corecursive_types_generic
 TypeAliases.forward_declared_alias_is_not_clobbered_by_prior_unification_with_any
-TypeAliases.general_require_multi_assign
 TypeAliases.generic_param_remap
 TypeAliases.mismatched_generic_pack_type_param
 TypeAliases.mismatched_generic_type_param
-TypeAliases.mutually_recursive_types_errors
 TypeAliases.mutually_recursive_types_restriction_not_ok_1
 TypeAliases.mutually_recursive_types_restriction_not_ok_2
 TypeAliases.mutually_recursive_types_swapsies_not_ok
@@ -543,7 +523,6 @@ TypeAliases.type_alias_fwd_declaration_is_precise
 TypeAliases.type_alias_local_mutation
 TypeAliases.type_alias_local_rename
 TypeAliases.type_alias_of_an_imported_recursive_generic_type
-TypeAliases.type_alias_of_an_imported_recursive_type
 TypeInfer.checking_should_not_ice
 TypeInfer.cyclic_follow
 TypeInfer.do_not_bind_a_free_table_to_a_union_containing_that_table
@@ -559,20 +538,21 @@ TypeInfer.tc_if_else_expressions_expected_type_1
 TypeInfer.tc_if_else_expressions_expected_type_2
 TypeInfer.tc_if_else_expressions_expected_type_3
 TypeInfer.tc_if_else_expressions_type_union
+TypeInfer.tc_interpolated_string_basic
+TypeInfer.tc_interpolated_string_constant_type
+TypeInfer.tc_interpolated_string_with_invalid_expression
 TypeInfer.type_infer_recursion_limit_no_ice
-TypeInfer.warn_on_lowercase_parent_property
 TypeInferAnyError.assign_prop_to_table_by_calling_any_yields_any
 TypeInferAnyError.can_get_length_of_any
-TypeInferAnyError.for_in_loop_iterator_is_any
 TypeInferAnyError.for_in_loop_iterator_is_any2
-TypeInferAnyError.for_in_loop_iterator_is_error
-TypeInferAnyError.for_in_loop_iterator_is_error2
 TypeInferAnyError.for_in_loop_iterator_returns_any
-TypeInferAnyError.for_in_loop_iterator_returns_any2
 TypeInferAnyError.length_of_error_type_does_not_produce_an_error
 TypeInferAnyError.replace_every_free_type_when_unifying_a_complex_function_with_any
+TypeInferAnyError.union_of_types_regression_test
 TypeInferClasses.call_base_method
 TypeInferClasses.call_instance_method
+TypeInferClasses.can_assign_to_prop_of_base_class_using_string
+TypeInferClasses.can_read_prop_of_base_class_using_string
 TypeInferClasses.class_type_mismatch_with_name_conflict
 TypeInferClasses.classes_can_have_overloaded_operators
 TypeInferClasses.classes_without_overloaded_operators_cannot_be_added
@@ -582,10 +562,13 @@ TypeInferClasses.higher_order_function_return_type_is_not_contravariant
 TypeInferClasses.higher_order_function_return_values_are_covariant
 TypeInferClasses.optional_class_field_access_error
 TypeInferClasses.table_class_unification_reports_sane_errors_for_missing_properties
+TypeInferClasses.table_indexers_are_invariant
+TypeInferClasses.table_properties_are_invariant
 TypeInferClasses.warn_when_prop_almost_matches
 TypeInferClasses.we_can_report_when_someone_is_trying_to_use_a_table_rather_than_a_class
 TypeInferFunctions.another_indirect_function_case_where_it_is_ok_to_provide_too_many_arguments
 TypeInferFunctions.another_recursive_local_function
+TypeInferFunctions.call_o_with_another_argument_after_foo_was_quantified
 TypeInferFunctions.calling_function_with_anytypepack_doesnt_leak_free_types
 TypeInferFunctions.calling_function_with_incorrect_argument_type_yields_errors_spanning_argument
 TypeInferFunctions.complicated_return_types_require_an_explicit_annotation
@@ -634,43 +617,23 @@ TypeInferFunctions.too_many_arguments
 TypeInferFunctions.too_many_return_values
 TypeInferFunctions.vararg_function_is_quantified
 TypeInferFunctions.vararg_functions_should_allow_calls_of_any_types_and_size
-TypeInferLoops.for_in_loop
 TypeInferLoops.for_in_loop_error_on_factory_not_returning_the_right_amount_of_values
-TypeInferLoops.for_in_loop_error_on_iterator_requiring_args_but_none_given
-TypeInferLoops.for_in_loop_on_error
-TypeInferLoops.for_in_loop_on_non_function
-TypeInferLoops.for_in_loop_should_fail_with_non_function_iterator
-TypeInferLoops.for_in_loop_where_iteratee_is_free
 TypeInferLoops.for_in_loop_with_custom_iterator
 TypeInferLoops.for_in_loop_with_next
-TypeInferLoops.for_in_with_a_custom_iterator_should_type_check
-TypeInferLoops.for_in_with_an_iterator_of_type_any
 TypeInferLoops.for_in_with_just_one_iterator_is_ok
-TypeInferLoops.fuzz_fail_missing_instantitation_follow
-TypeInferLoops.ipairs_produces_integral_indices
-TypeInferLoops.loop_iter_basic
 TypeInferLoops.loop_iter_iter_metamethod
 TypeInferLoops.loop_iter_no_indexer_nonstrict
-TypeInferLoops.loop_iter_no_indexer_strict
 TypeInferLoops.loop_iter_trailing_nil
 TypeInferLoops.loop_typecheck_crash_on_empty_optional
-TypeInferLoops.properly_infer_iteratee_is_a_free_table
 TypeInferLoops.unreachable_code_after_infinite_loop
 TypeInferLoops.varlist_declared_by_for_in_loop_should_be_free
-TypeInferModules.do_not_modify_imported_types
-TypeInferModules.do_not_modify_imported_types_2
-TypeInferModules.do_not_modify_imported_types_3
-TypeInferModules.general_require_call_expression
+TypeInferModules.custom_require_global
 TypeInferModules.general_require_type_mismatch
 TypeInferModules.module_type_conflict
 TypeInferModules.module_type_conflict_instantiated
-TypeInferModules.require
 TypeInferModules.require_a_variadic_function
-TypeInferModules.require_failed_module
-TypeInferModules.require_module_that_does_not_export
 TypeInferModules.require_types
 TypeInferModules.type_error_of_unknown_qualified_type
-TypeInferModules.warn_if_you_try_to_require_a_non_modulescript
 TypeInferOOP.CheckMethodsOfSealed
 TypeInferOOP.dont_suggest_using_colon_rather_than_dot_if_another_overload_works
 TypeInferOOP.dont_suggest_using_colon_rather_than_dot_if_it_wont_help_2
@@ -725,7 +688,6 @@ TypeInferOperators.typecheck_unary_minus_error
 TypeInferOperators.unary_not_is_boolean
 TypeInferOperators.unknown_type_in_comparison
 TypeInferOperators.UnknownGlobalCompoundAssign
-TypeInferPrimitives.cannot_call_primitives
 TypeInferPrimitives.CheckMethodsOfNumber
 TypeInferPrimitives.string_function_other
 TypeInferPrimitives.string_index
@@ -768,7 +730,6 @@ TypePackTests.type_alias_type_packs_nested
 TypePackTests.type_pack_hidden_free_tail_infinite_growth
 TypePackTests.type_pack_type_parameters
 TypePackTests.varargs_inference_through_multiple_scopes
-TypePackTests.variadic_argument_tail
 TypePackTests.variadic_pack_syntax
 TypePackTests.variadic_packs
 TypeSingletons.bool_singleton_subtype
@@ -793,7 +754,6 @@ TypeSingletons.string_singletons_escape_chars
 TypeSingletons.string_singletons_mismatch
 TypeSingletons.table_insert_with_a_singleton_argument
 TypeSingletons.table_properties_type_error_escapes
-TypeSingletons.tagged_unions_immutable_tag
 TypeSingletons.tagged_unions_using_singletons
 TypeSingletons.taking_the_length_of_string_singleton
 TypeSingletons.taking_the_length_of_union_of_string_singleton
diff --git a/tools/test_dcr.py b/tools/test_dcr.py
index da33706c..db932253 100644
--- a/tools/test_dcr.py
+++ b/tools/test_dcr.py
@@ -84,12 +84,16 @@ def main():
 
     failList = loadFailList()
 
+    commandLine = [
+        args.path,
+        "--reporters=xml",
+        "--fflags=true,DebugLuauDeferredConstraintResolution=true",
+    ]
+
+    print('>', ' '.join(commandLine), file=sys.stderr)
+
     p = sp.Popen(
-        [
-            args.path,
-            "--reporters=xml",
-            "--fflags=true,DebugLuauDeferredConstraintResolution=true",
-        ],
+        commandLine,
         stdout=sp.PIPE,
     )
 
@@ -122,7 +126,7 @@ def main():
         with open(FAIL_LIST_PATH, "w", newline="\n") as f:
             for name in newFailList:
                 print(name, file=f)
-        print("Updated faillist.txt")
+        print("Updated faillist.txt", file=sys.stderr)
 
     if handler.numSkippedTests > 0:
         print(