diff --git a/src/Draco.Compiler.Cli/Program.cs b/src/Draco.Compiler.Cli/Program.cs
index 2a4900ce3..f9a56a57a 100644
--- a/src/Draco.Compiler.Cli/Program.cs
+++ b/src/Draco.Compiler.Cli/Program.cs
@@ -112,7 +112,7 @@ private static void CompileCommand(FileInfo[] input, FileInfo output, DirectoryI
         var compilation = Compilation.Create(
             syntaxTrees: syntaxTrees,
             metadataReferences: references
-                .Select(r => MetadataReference.FromPeStream(r.OpenRead()))
+                .Select(r => MetadataReference.FromFile(r.FullName))
                 .ToImmutableArray(),
             rootModulePath: rootModule?.FullName,
             outputPath: path,
@@ -133,7 +133,7 @@ private static void RunCommand(FileInfo[] input, DirectoryInfo? rootModule, File
         var compilation = Compilation.Create(
             syntaxTrees: syntaxTrees,
             metadataReferences: references
-                .Select(r => MetadataReference.FromPeStream(r.OpenRead()))
+                .Select(r => MetadataReference.FromFile(r.FullName))
                 .ToImmutableArray(),
             rootModulePath: rootModule?.FullName);
         var execResult = Script.ExecuteAsProgram(compilation);
diff --git a/src/Draco.Compiler.Tests/EndToEnd/CompilingCodeTests.cs b/src/Draco.Compiler.Tests/EndToEnd/CompilingCodeTests.cs
index fb815ec9f..e1cc369a0 100644
--- a/src/Draco.Compiler.Tests/EndToEnd/CompilingCodeTests.cs
+++ b/src/Draco.Compiler.Tests/EndToEnd/CompilingCodeTests.cs
@@ -799,4 +799,25 @@ public void GlobalInferredFromBlock()
         Assert.Single(l);
         Assert.Equal(1, l[0]);
     }
+
+    [Fact]
+    public void EnumEqualityOperators()
+    {
+        var assembly = Compile("""
+            import System;
+
+            public func equate(a: StringComparison, b: StringComparison): bool = a == b;
+            public func inequate(a: StringComparison, b: StringComparison): bool = a != b;
+            """);
+
+        var eq1 = Invoke<bool>(assembly, "equate", StringComparison.Ordinal, StringComparison.Ordinal);
+        var eq2 = Invoke<bool>(assembly, "equate", StringComparison.Ordinal, StringComparison.OrdinalIgnoreCase);
+        var neq1 = Invoke<bool>(assembly, "inequate", StringComparison.Ordinal, StringComparison.Ordinal);
+        var neq2 = Invoke<bool>(assembly, "inequate", StringComparison.Ordinal, StringComparison.OrdinalIgnoreCase);
+
+        Assert.True(eq1);
+        Assert.False(eq2);
+        Assert.False(neq1);
+        Assert.True(neq2);
+    }
 }
diff --git a/src/Draco.Compiler.Tests/Scripting/ScriptTests.cs b/src/Draco.Compiler.Tests/Scripting/ScriptTests.cs
index 7c4d06fd6..2f240cea7 100644
--- a/src/Draco.Compiler.Tests/Scripting/ScriptTests.cs
+++ b/src/Draco.Compiler.Tests/Scripting/ScriptTests.cs
@@ -27,4 +27,23 @@ public void BasicAssignmentAndAddition()
         Assert.True(result.Success);
         Assert.Equal(7, result.Value);
     }
+
+    [Fact]
+    public void SyntaxErrorInScript()
+    {
+        // Arrange
+        var script = Script.Create<int>("""
+            var x = ;
+            """,
+            metadataReferences: Basic.Reference.Assemblies.Net80.ReferenceInfos.All
+                .Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes)))
+                .ToImmutableArray());
+
+        // Act
+        var result = script.Execute();
+
+        // Assert
+        Assert.False(result.Success);
+        Assert.NotEmpty(result.Diagnostics);
+    }
 }
diff --git a/src/Draco.Compiler.Tests/Semantics/DocumentationCommentsTests.cs b/src/Draco.Compiler.Tests/Semantics/DocumentationCommentsTests.cs
index d5ff574ed..56f112969 100644
--- a/src/Draco.Compiler.Tests/Semantics/DocumentationCommentsTests.cs
+++ b/src/Draco.Compiler.Tests/Semantics/DocumentationCommentsTests.cs
@@ -214,7 +214,7 @@ public void TypeDocumentationFromMetadata()
         var testRef = CompileCSharpToMetadataRef($$"""
             /// {{docs}}
             public class TestClass { }
-            """, xmlStream: xmlStream).WithDocumentation(xmlStream);
+            """, xmlStream: xmlStream);
 
         var call = tree.FindInChildren<NameExpressionSyntax>(0);
 
@@ -258,7 +258,7 @@ public class TestClass
                 /// {{docs}}
                 public class NestedTestClass { }
             }
-            """, xmlStream: xmlStream).WithDocumentation(xmlStream);
+            """, xmlStream: xmlStream);
 
         var call = tree.FindInChildren<NameExpressionSyntax>(0);
 
@@ -304,7 +304,7 @@ public static class TestClass
                 // Just so i can use it in draco
                 public static int foo = 0;
             }
-            """, xmlStream: xmlStream).WithDocumentation(xmlStream);
+            """, xmlStream: xmlStream);
 
         var @class = tree.FindInChildren<MemberExpressionSyntax>(0).Accessed;
 
@@ -348,7 +348,7 @@ public class TestClass
                 /// {{docs}}
                 public void TestMethod(int arg1, string arg2) { }
             }
-            """, xmlStream: xmlStream).WithDocumentation(xmlStream);
+            """, xmlStream: xmlStream);
 
         var call = tree.FindInChildren<NameExpressionSyntax>(0);
 
@@ -395,7 +395,7 @@ public class TestClass
                 /// {{docs}}
                 public void TestMethod() { }
             }
-            """, xmlStream: xmlStream).WithDocumentation(xmlStream);
+            """, xmlStream: xmlStream);
 
         var call = tree.FindInChildren<NameExpressionSyntax>(0);
 
@@ -440,7 +440,7 @@ public class TestClass
                 /// {{docs}}
                 public int TestField = 5;
             }
-            """, xmlStream: xmlStream).WithDocumentation(xmlStream);
+            """, xmlStream: xmlStream);
 
         var call = tree.FindInChildren<NameExpressionSyntax>(0);
 
@@ -485,7 +485,7 @@ public class TestClass
                 /// {{docs}}
                 public int TestProperty { get; }
             }
-            """, xmlStream: xmlStream).WithDocumentation(xmlStream);
+            """, xmlStream: xmlStream);
 
         var call = tree.FindInChildren<NameExpressionSyntax>(0);
 
@@ -534,7 +534,7 @@ public class TestClass<T>
                 /// {{methodDocs}}
                 public void TestMethod<U>(T arg1, T arg2, U arg3) { }
             }
-            """, xmlStream: xmlStream).WithDocumentation(xmlStream);
+            """, xmlStream: xmlStream);
 
         var call = tree.FindInChildren<CallExpressionSyntax>(0);
 
@@ -594,7 +594,7 @@ public class TestClass
                 {{CreateXmlDocComment(originalDocs)}}
                 public int TestMethod<T>(int arg1, int arg2) => arg1 + arg2; 
             }
-            """, xmlStream: xmlStream).WithDocumentation(xmlStream);
+            """, xmlStream: xmlStream);
 
         var call = tree.FindInChildren<NameExpressionSyntax>(0);
 
diff --git a/src/Draco.Compiler.Tests/Semantics/TypeCheckingTests.cs b/src/Draco.Compiler.Tests/Semantics/TypeCheckingTests.cs
index 050805de8..5766f0de7 100644
--- a/src/Draco.Compiler.Tests/Semantics/TypeCheckingTests.cs
+++ b/src/Draco.Compiler.Tests/Semantics/TypeCheckingTests.cs
@@ -2287,4 +2287,106 @@ public void InferredArrayElementTypeFromUsage()
         var intArray = compilation.WellKnownTypes.InstantiateArray(compilation.WellKnownTypes.SystemInt32);
         Assert.True(SymbolEqualityComparer.Default.Equals(intArray, aSym.Type));
     }
+
+    [Fact]
+    public void ArrayIndexResultHasTheRightType()
+    {
+        // func main() {
+        //     val a = Array<int32>(3);
+        //     val x = a[0];
+        // }
+
+        var main = SyntaxTree.Create(CompilationUnit(FunctionDeclaration(
+            "main",
+            ParameterList(),
+            null,
+            BlockFunctionBody(
+                DeclarationStatement(ImmutableVariableDeclaration(
+                    "a",
+                    null,
+                    CallExpression(GenericExpression(NameExpression("Array"), NameType("int32")), LiteralExpression(3)))),
+                DeclarationStatement(ImmutableVariableDeclaration(
+                    "x",
+                    null,
+                    IndexExpression(NameExpression("a"), LiteralExpression(0))))))));
+
+        // Act
+        var compilation = CreateCompilation(main);
+        var semanticModel = compilation.GetSemanticModel(main);
+
+        var diags = semanticModel.Diagnostics;
+        var xDecl = main.FindInChildren<VariableDeclarationSyntax>(1);
+        var xSym = GetInternalSymbol<LocalSymbol>(semanticModel.GetDeclaredSymbol(xDecl));
+
+        // Assert
+        Assert.Empty(diags);
+        Assert.False(xSym.IsError);
+        Assert.Equal(compilation.WellKnownTypes.SystemInt32, xSym.Type);
+    }
+
+    [Fact]
+    public void ArrayIteratorVariableCorrectlyInferredInForLoop()
+    {
+        // func main() {
+        //     val a = Array<int32>(3);
+        //     for (x in a) { }
+        // }
+
+        var main = SyntaxTree.Create(CompilationUnit(FunctionDeclaration(
+            "main",
+            ParameterList(),
+            null,
+            BlockFunctionBody(
+                DeclarationStatement(ImmutableVariableDeclaration(
+                    "a",
+                    null,
+                    CallExpression(GenericExpression(NameExpression("Array"), NameType("int32")), LiteralExpression(3)))),
+                ExpressionStatement(ForExpression(
+                    "x",
+                    NameExpression("a"),
+                    BlockExpression()))))));
+
+        // Act
+        var compilation = CreateCompilation(main);
+        var semanticModel = compilation.GetSemanticModel(main);
+
+        var diags = semanticModel.Diagnostics;
+        var xDecl = main.FindInChildren<ForExpressionSyntax>().Iterator;
+        var xSym = GetInternalSymbol<LocalSymbol>(semanticModel.GetDeclaredSymbol(xDecl));
+
+        // Assert
+        Assert.Empty(diags);
+        Assert.False(xSym.IsError);
+        Assert.Equal(compilation.WellKnownTypes.SystemInt32, xSym.Type);
+    }
+
+    [Fact]
+    public void ErrorExpressionsDoNotCascadeErrorsInOverloading()
+    {
+        // import System.Numerics;
+        //
+        // func foo(): Vector3 = Vector3() + Vector3();
+
+        var main = SyntaxTree.Create(CompilationUnit(
+            ImportDeclaration("System", "Numerics"),
+            FunctionDeclaration(
+                "foo",
+                ParameterList(),
+                NameType("Vector3"),
+                InlineFunctionBody(BinaryExpression(
+                    CallExpression(NameExpression("Vector3")),
+                    Plus,
+                    CallExpression(NameExpression("Vector3")))))));
+
+        // Act
+        var compilation = CreateCompilation(main);
+        var semanticModel = compilation.GetSemanticModel(main);
+        var diags = semanticModel.Diagnostics;
+
+        // Assert
+        Assert.Equal(2, diags.Length);
+        AssertDiagnostic(diags, TypeCheckingErrors.NoMatchingOverload);
+
+        Assert.True(diags.All(d => !d.ToString().Contains("operator", StringComparison.OrdinalIgnoreCase)));
+    }
 }
diff --git a/src/Draco.Compiler.Tests/TestUtilities.cs b/src/Draco.Compiler.Tests/TestUtilities.cs
index 8e5bf3b84..6a9731a6e 100644
--- a/src/Draco.Compiler.Tests/TestUtilities.cs
+++ b/src/Draco.Compiler.Tests/TestUtilities.cs
@@ -15,7 +15,7 @@ internal static class TestUtilities
     public static MetadataReference CompileCSharpToMetadataRef(string code, string assemblyName = DefaultAssemblyName, IEnumerable<Stream>? aditionalReferences = null, Stream? xmlStream = null)
     {
         var stream = CompileCSharpToStream(code, assemblyName, aditionalReferences, xmlStream);
-        return MetadataReference.FromPeStream(stream);
+        return MetadataReference.FromPeStream(stream, xmlStream);
     }
 
     public static Stream CompileCSharpToStream(string code, string assemblyName = DefaultAssemblyName, IEnumerable<Stream>? aditionalReferences = null, Stream? xmlStream = null)
diff --git a/src/Draco.Compiler/Api/MetadataReference.cs b/src/Draco.Compiler/Api/MetadataReference.cs
index 3fc6afe29..1b326b34a 100644
--- a/src/Draco.Compiler/Api/MetadataReference.cs
+++ b/src/Draco.Compiler/Api/MetadataReference.cs
@@ -22,12 +22,28 @@ public abstract class MetadataReference
     /// </summary>
     public abstract XmlDocument? Documentation { get; }
 
+    /// <summary>
+    /// Creates a metadata reference reading up the given file.
+    /// </summary>
+    /// <param name="path">The path to the file to read.</param>
+    /// <returns>The <see cref="MetadataReference"/> created from the file at <paramref name="path"/>.</returns>
+    public static MetadataReference FromFile(string path)
+    {
+        // NOTE: We could add a bool to turn off fetching the docs
+        var peStream = File.OpenRead(path);
+        // We assume the docs are under the same path, same name but with .xml extension
+        var docPath = Path.ChangeExtension(path, ".xml");
+        var docStream = File.Exists(docPath) ? File.OpenRead(docPath) : null;
+        return FromPeStream(peStream, docStream);
+    }
+
     /// <summary>
     /// Creates a metadata reference from the given assembly.
     /// </summary>
     /// <param name="assembly">The assembly to create a metadata reader from.</param>
+    /// <param name="documentation">The XML documentation for the assembly.</param>
     /// <returns>The <see cref="MetadataReference"/> created from <paramref name="assembly"/>.</returns>
-    public static MetadataReference FromAssembly(Assembly assembly)
+    public static MetadataReference FromAssembly(Assembly assembly, XmlDocument? documentation = null)
     {
         unsafe
         {
@@ -37,7 +53,7 @@ public static MetadataReference FromAssembly(Assembly assembly)
             }
 
             var reader = new MetadataReader(blob, length);
-            return new MetadataReaderReference(reader);
+            return new MetadataReaderReference(reader, documentation);
         }
     }
 
@@ -45,29 +61,37 @@ public static MetadataReference FromAssembly(Assembly assembly)
     /// Creates a metadata reference from the given PE stream.
     /// </summary>
     /// <param name="peStream">The PE stream to create the metadata reference from.</param>
+    /// <param name="documentation">The XML documentation for the assembly.</param>
     /// <returns>The <see cref="MetadataReference"/> reading up from <paramref name="peStream"/>.</returns>
-    public static MetadataReference FromPeStream(Stream peStream)
+    public static MetadataReference FromPeStream(Stream peStream, XmlDocument? documentation = null)
     {
         var peReader = new PEReader(peStream);
         var metadataReader = peReader.GetMetadataReader();
-        return new MetadataReaderReference(metadataReader);
+        return new MetadataReaderReference(metadataReader, documentation);
     }
 
     /// <summary>
-    /// Adds xml documentation to this metadata reference.
+    /// Creates a metadata reference from the given PE stream.
     /// </summary>
-    /// <param name="xmlStream">The stream with the xml documentation.</param>
-    /// <returns>New metadata reference containing xml documentation.</returns>
-    public MetadataReference WithDocumentation(Stream xmlStream)
+    /// <param name="peStream">The PE stream to create the metadata reference from.</param>
+    /// <param name="xmlDocStream">The stream to read up XML documentation from for the assembly.</param>
+    /// <returns>The <see cref="MetadataReference"/> reading up from <paramref name="peStream"/>.</returns>
+    public static MetadataReference FromPeStream(Stream peStream, Stream? xmlDocStream)
     {
-        var doc = new XmlDocument();
-        doc.Load(xmlStream);
-        return new MetadataReaderReference(this.MetadataReader, doc);
+        var peReader = new PEReader(peStream);
+        var metadataReader = peReader.GetMetadataReader();
+        var docXml = null as XmlDocument;
+        if (xmlDocStream is not null)
+        {
+            docXml = new XmlDocument();
+            docXml.Load(xmlDocStream);
+        }
+        return new MetadataReaderReference(metadataReader, docXml);
     }
 
     private sealed class MetadataReaderReference(
         MetadataReader metadataReader,
-        XmlDocument? documentation = null) : MetadataReference
+        XmlDocument? documentation) : MetadataReference
     {
         public override MetadataReader MetadataReader { get; } = metadataReader;
         public override XmlDocument? Documentation { get; } = documentation;
diff --git a/src/Draco.Compiler/Api/Syntax/SyntaxTree.cs b/src/Draco.Compiler/Api/Syntax/SyntaxTree.cs
index 3842c2bdd..ee7b31d85 100644
--- a/src/Draco.Compiler/Api/Syntax/SyntaxTree.cs
+++ b/src/Draco.Compiler/Api/Syntax/SyntaxTree.cs
@@ -75,7 +75,7 @@ internal static SyntaxTree ParseScript(ISourceReader sourceReader)
         // Parse a repl entry
         var node = parser.ParseScriptEntry();
         // Make it into a tree
-        return Create(node);
+        return Create(node, syntaxDiagnostics: syntaxDiagnostics);
     }
 
     /// <summary>
diff --git a/src/Draco.Compiler/Internal/Binding/BinderFacts.cs b/src/Draco.Compiler/Internal/Binding/BinderFacts.cs
index bfcf229de..c16c1aae9 100644
--- a/src/Draco.Compiler/Internal/Binding/BinderFacts.cs
+++ b/src/Draco.Compiler/Internal/Binding/BinderFacts.cs
@@ -3,7 +3,7 @@
 using System.Text;
 using Draco.Compiler.Api.Syntax;
 using Draco.Compiler.Internal.Symbols;
-using Draco.Compiler.Internal.Symbols.Synthetized;
+using Draco.Compiler.Internal.Symbols.Synthetized.Array;
 
 namespace Draco.Compiler.Internal.Binding;
 
diff --git a/src/Draco.Compiler/Internal/Binding/Binder_Expression.cs b/src/Draco.Compiler/Internal/Binding/Binder_Expression.cs
index f78f72b0b..70ea2f6ff 100644
--- a/src/Draco.Compiler/Internal/Binding/Binder_Expression.cs
+++ b/src/Draco.Compiler/Internal/Binding/Binder_Expression.cs
@@ -13,6 +13,7 @@
 using Draco.Compiler.Internal.Symbols;
 using Draco.Compiler.Internal.Symbols.Error;
 using Draco.Compiler.Internal.Symbols.Synthetized;
+using Draco.Compiler.Internal.Symbols.Synthetized.Array;
 
 namespace Draco.Compiler.Internal.Binding;
 
@@ -634,16 +635,8 @@ private async BindingTask<BoundExpression> BindMemberExpression(MemberExpression
             case FieldSymbol field:
                 return new BoundFieldExpression(syntax, receiver, field);
             case PropertySymbol prop:
-                // It could be array length
-                if (prop.GenericDefinition is ArrayLengthPropertySymbol)
-                {
-                    return new BoundArrayLengthExpression(syntax, receiver);
-                }
-                else
-                {
-                    var getter = GetGetterSymbol(syntax, prop, diagnostics);
-                    return new BoundPropertyGetExpression(syntax, receiver, getter);
-                }
+                var getter = GetGetterSymbol(syntax, prop, diagnostics);
+                return new BoundPropertyGetExpression(syntax, receiver, getter);
             default:
                 // TODO
                 throw new NotImplementedException();
@@ -672,8 +665,7 @@ private async BindingTask<BoundExpression> BindIndexExpression(IndexExpressionSy
         var receiver = await receiverTask;
         var indexer = await indexerTask;
 
-        var arrayIndexProperty = (indexer.GenericDefinition as IPropertyAccessorSymbol)?.Property as ArrayIndexPropertySymbol;
-        if (arrayIndexProperty is not null)
+        if (receiver.TypeRequired.IsArrayType)
         {
             // Array getter
             return new BoundArrayAccessExpression(syntax, receiver, await BindingTask.WhenAll(argsTask));
diff --git a/src/Draco.Compiler/Internal/Binding/Binder_Lvalue.cs b/src/Draco.Compiler/Internal/Binding/Binder_Lvalue.cs
index cd99896da..2c6818e92 100644
--- a/src/Draco.Compiler/Internal/Binding/Binder_Lvalue.cs
+++ b/src/Draco.Compiler/Internal/Binding/Binder_Lvalue.cs
@@ -8,7 +8,7 @@
 using Draco.Compiler.Internal.Diagnostics;
 using Draco.Compiler.Internal.Solver;
 using Draco.Compiler.Internal.Symbols;
-using Draco.Compiler.Internal.Symbols.Synthetized;
+using Draco.Compiler.Internal.Symbols.Synthetized.Array;
 
 namespace Draco.Compiler.Internal.Binding;
 
@@ -153,8 +153,7 @@ private async BindingTask<BoundLvalue> BindIndexLvalue(IndexExpressionSyntax syn
         var receiver = await receiverTask;
         var indexer = await indexerTask;
 
-        var arrayIndexProperty = (indexer.GenericDefinition as IPropertyAccessorSymbol)?.Property as ArrayIndexPropertySymbol;
-        if (arrayIndexProperty is not null)
+        if (receiver.TypeRequired.IsArrayType)
         {
             return new BoundArrayAccessLvalue(
                 syntax,
diff --git a/src/Draco.Compiler/Internal/BoundTree/BoundNode.cs b/src/Draco.Compiler/Internal/BoundTree/BoundNode.cs
index c0ef307d3..ec2791867 100644
--- a/src/Draco.Compiler/Internal/BoundTree/BoundNode.cs
+++ b/src/Draco.Compiler/Internal/BoundTree/BoundNode.cs
@@ -2,7 +2,7 @@
 using System.Linq;
 using Draco.Compiler.Api.Syntax;
 using Draco.Compiler.Internal.Symbols;
-using Draco.Compiler.Internal.Symbols.Synthetized;
+using Draco.Compiler.Internal.Symbols.Synthetized.Array;
 
 namespace Draco.Compiler.Internal.BoundTree;
 
diff --git a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs
index e0cfa9b6b..28fac7004 100644
--- a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs
+++ b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs
@@ -14,7 +14,7 @@
 using Draco.Compiler.Internal.Symbols.Metadata;
 using Draco.Compiler.Internal.Symbols.Script;
 using Draco.Compiler.Internal.Symbols.Source;
-using Draco.Compiler.Internal.Symbols.Synthetized;
+using Draco.Compiler.Internal.Symbols.Synthetized.Array;
 
 namespace Draco.Compiler.Internal.Codegen;
 
diff --git a/src/Draco.Compiler/Internal/Documentation/Extractors/XmlDocumentationExtractor.cs b/src/Draco.Compiler/Internal/Documentation/Extractors/XmlDocumentationExtractor.cs
index f7a292838..d0ca74533 100644
--- a/src/Draco.Compiler/Internal/Documentation/Extractors/XmlDocumentationExtractor.cs
+++ b/src/Draco.Compiler/Internal/Documentation/Extractors/XmlDocumentationExtractor.cs
@@ -93,13 +93,24 @@ private ImmutableArray<DocumentationElement> ExtractElementsFromNode(XmlNode nod
         return elements.ToImmutable();
     }
 
-    private ReferenceDocumentationElement ConstructReference(XmlNode node)
+    private DocumentationElement ConstructReference(XmlNode node)
     {
+        // It can be a 'cref' or a 'langword'
         var cref = node.Attributes?["cref"]?.Value;
-        var symbol = this.GetSymbolFromDocumentationName(cref ?? string.Empty)
-            // NOTE: The first two characters of the link is the documentation prefix
-            ?? new PrimitiveTypeSymbol(cref?[2..] ?? string.Empty, false);
-        return new ReferenceDocumentationElement(symbol, string.IsNullOrEmpty(node.InnerText) ? null : node.InnerText);
+        if (cref is not null)
+        {
+            var symbol = this.GetSymbolFromDocumentationName(cref)
+                // NOTE: The first two characters of the link is the documentation prefix
+                ?? new PrimitiveTypeSymbol(cref[2..], false);
+            return new ReferenceDocumentationElement(symbol, node.InnerText.Length == 0 ? null : node.InnerText);
+        }
+        var langword = node.Attributes?["langword"]?.Value;
+        if (langword is not null)
+        {
+            return new TextDocumentationElement(langword);
+        }
+        // Bail out with some default
+        return new TextDocumentationElement($"unknown reference element: {node.InnerText}");
     }
 
     private Symbol? GetSymbolFromDocumentationName(string documentationName) =>
diff --git a/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Operations.cs b/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Operations.cs
index b3c9c5bd1..f596e89de 100644
--- a/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Operations.cs
+++ b/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Operations.cs
@@ -4,6 +4,7 @@
 using Draco.Compiler.Internal.Symbols;
 using Draco.Compiler.Internal.Symbols.Error;
 using Draco.Compiler.Internal.Symbols.Synthetized;
+using Draco.Compiler.Internal.Symbols.Synthetized.Array;
 
 namespace Draco.Compiler.Internal.Solver;
 
diff --git a/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Rules.cs b/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Rules.cs
index e93f4227e..a8aee263e 100644
--- a/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Rules.cs
+++ b/src/Draco.Compiler/Internal/Solver/ConstraintSolver_Rules.cs
@@ -293,10 +293,14 @@ private IEnumerable<Rule> ConstructRules(DiagnosticBag diagnostics) => [
                     UnifyAsserted(overload.ReturnType, WellKnownTypes.ErrorType);
                     // Best-effort shape approximation
                     var errorSymbol = new ErrorFunctionSymbol(overload.Candidates.Arguments.Length);
-                    overload.ReportDiagnostic(diagnostics, diag => diag
-                        .WithTemplate(TypeCheckingErrors.NoMatchingOverload)
-                        .WithFormatArgs(overload.FunctionName));
                     overload.CompletionSource.SetResult(errorSymbol);
+                    // NOTE: If the arguments have an error, we don't report an error here to not cascade errors
+                    if (overload.Candidates.Arguments.All(a => !a.Type.Substitution.IsError))
+                    {
+                        overload.ReportDiagnostic(diagnostics, diag => diag
+                            .WithTemplate(TypeCheckingErrors.NoMatchingOverload)
+                            .WithFormatArgs(overload.FunctionName));
+                    }
                     return;
                 }
 
@@ -306,10 +310,14 @@ private IEnumerable<Rule> ConstructRules(DiagnosticBag diagnostics) => [
                     // Best-effort shape approximation
                     UnifyAsserted(overload.ReturnType, WellKnownTypes.ErrorType);
                     var errorSymbol = new ErrorFunctionSymbol(overload.Candidates.Arguments.Length);
-                    overload.ReportDiagnostic(diagnostics, diag => diag
-                        .WithTemplate(TypeCheckingErrors.AmbiguousOverloadedCall)
-                        .WithFormatArgs(overload.FunctionName, string.Join(", ", overload.Candidates)));
                     overload.CompletionSource.SetResult(errorSymbol);
+                    // NOTE: If the arguments have an error, we don't report an error here to not cascade errors
+                    if (overload.Candidates.Arguments.All(a => !a.Type.Substitution.IsError))
+                    {
+                        overload.ReportDiagnostic(diagnostics, diag => diag
+                            .WithTemplate(TypeCheckingErrors.AmbiguousOverloadedCall)
+                            .WithFormatArgs(overload.FunctionName, string.Join(", ", overload.Candidates)));
+                    }
                     return;
                 }
 
diff --git a/src/Draco.Compiler/Internal/Symbols/AliasSymbol.cs b/src/Draco.Compiler/Internal/Symbols/AliasSymbol.cs
index 45c9eb5c1..af614b4cc 100644
--- a/src/Draco.Compiler/Internal/Symbols/AliasSymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/AliasSymbol.cs
@@ -8,6 +8,7 @@ namespace Draco.Compiler.Internal.Symbols;
 internal abstract class AliasSymbol : Symbol, IMemberSymbol
 {
     public bool IsStatic => true;
+    public bool IsExplicitImplementation => false;
 
     /// <summary>
     /// The symbol being aliased.
diff --git a/src/Draco.Compiler/Internal/Symbols/Error/ErrorMemberSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Error/ErrorMemberSymbol.cs
index 51e3534de..b8dbef9e6 100644
--- a/src/Draco.Compiler/Internal/Symbols/Error/ErrorMemberSymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/Error/ErrorMemberSymbol.cs
@@ -15,6 +15,7 @@ internal sealed class ErrorMemberSymbol : Symbol, ITypedSymbol, IMemberSymbol
     public TypeSymbol Type => WellKnownTypes.ErrorType;
 
     public bool IsStatic => true;
+    public bool IsExplicitImplementation => false;
 
     private ErrorMemberSymbol()
     {
diff --git a/src/Draco.Compiler/Internal/Symbols/Error/ErrorPropertySymbol.cs b/src/Draco.Compiler/Internal/Symbols/Error/ErrorPropertySymbol.cs
index e141bec2e..afe543719 100644
--- a/src/Draco.Compiler/Internal/Symbols/Error/ErrorPropertySymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/Error/ErrorPropertySymbol.cs
@@ -13,6 +13,7 @@ public static FunctionSymbol CreateIndexerSet(int indicesCount) =>
 
     public override bool IsError => true;
     public override bool IsStatic => true;
+    public override bool IsExplicitImplementation => false;
     public override bool IsIndexer => false;
     public override TypeSymbol Type => WellKnownTypes.ErrorType;
 
diff --git a/src/Draco.Compiler/Internal/Symbols/Error/ErrorTypeSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Error/ErrorTypeSymbol.cs
index ee0b8cb8e..f3a63455c 100644
--- a/src/Draco.Compiler/Internal/Symbols/Error/ErrorTypeSymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/Error/ErrorTypeSymbol.cs
@@ -1,5 +1,5 @@
-using Draco.Compiler.Internal.Symbols.Generic;
 using System.Collections.Immutable;
+using Draco.Compiler.Internal.Symbols.Generic;
 
 namespace Draco.Compiler.Internal.Symbols.Error;
 
diff --git a/src/Draco.Compiler/Internal/Symbols/FieldSymbol.cs b/src/Draco.Compiler/Internal/Symbols/FieldSymbol.cs
index d309176ae..643c48412 100644
--- a/src/Draco.Compiler/Internal/Symbols/FieldSymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/FieldSymbol.cs
@@ -10,6 +10,7 @@ namespace Draco.Compiler.Internal.Symbols;
 internal abstract class FieldSymbol : VariableSymbol, IMemberSymbol
 {
     public bool IsStatic => false;
+    public bool IsExplicitImplementation => false;
 
     // NOTE: Override for covariant return type
     public override FieldSymbol? GenericDefinition => null;
diff --git a/src/Draco.Compiler/Internal/Symbols/FunctionSymbol.cs b/src/Draco.Compiler/Internal/Symbols/FunctionSymbol.cs
index 00b80b1b3..beda51cfb 100644
--- a/src/Draco.Compiler/Internal/Symbols/FunctionSymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/FunctionSymbol.cs
@@ -85,6 +85,7 @@ public delegate IOperand CodegenDelegate(
     public abstract TypeSymbol ReturnType { get; }
 
     public virtual bool IsStatic => true;
+    public virtual bool IsExplicitImplementation => false;
 
     /// <summary>
     /// If true, this is a virtual function.
diff --git a/src/Draco.Compiler/Internal/Symbols/Generic/PropertyInstanceSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Generic/PropertyInstanceSymbol.cs
index ca58929ea..1168e9b5a 100644
--- a/src/Draco.Compiler/Internal/Symbols/Generic/PropertyInstanceSymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/Generic/PropertyInstanceSymbol.cs
@@ -26,6 +26,8 @@ internal sealed class PropertyInstanceSymbol(
 
     public override bool IsStatic => this.GenericDefinition.IsStatic;
 
+    public override bool IsExplicitImplementation => this.GenericDefinition.IsExplicitImplementation;
+
     public override Symbol? ContainingSymbol { get; } = containingSymbol;
     public override PropertySymbol GenericDefinition { get; } = genericDefinition;
 
diff --git a/src/Draco.Compiler/Internal/Symbols/Generic/TypeInstanceSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Generic/TypeInstanceSymbol.cs
index dc92c09d7..66895084d 100644
--- a/src/Draco.Compiler/Internal/Symbols/Generic/TypeInstanceSymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/Generic/TypeInstanceSymbol.cs
@@ -51,10 +51,13 @@ public override ImmutableArray<TypeSymbol> GenericArguments
     public override ImmutableArray<TypeSymbol> ImmediateBaseTypes => this.GenericDefinition.ImmediateBaseTypes
         .Select(x => x.GenericInstantiate(x.ContainingSymbol, this.Context))
         .ToImmutableArray();
+    public override bool IsAbstract => this.GenericDefinition.IsAbstract;
     public override bool IsTypeVariable => this.GenericDefinition.IsTypeVariable;
     public override bool IsValueType => this.GenericDefinition.IsValueType;
     public override bool IsDelegateType => this.GenericDefinition.IsDelegateType;
     public override bool IsInterface => this.GenericDefinition.IsInterface;
+    public override bool IsArrayType => this.GenericDefinition.IsArrayType;
+    public override bool IsSealed => this.GenericDefinition.IsSealed;
     public override string Name => this.GenericDefinition.Name;
 
     public override Symbol? ContainingSymbol { get; } = containingSymbol;
diff --git a/src/Draco.Compiler/Internal/Symbols/GlobalSymbol.cs b/src/Draco.Compiler/Internal/Symbols/GlobalSymbol.cs
index cfbc261f5..fc65757cc 100644
--- a/src/Draco.Compiler/Internal/Symbols/GlobalSymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/GlobalSymbol.cs
@@ -10,6 +10,7 @@ namespace Draco.Compiler.Internal.Symbols;
 internal abstract partial class GlobalSymbol : VariableSymbol, IMemberSymbol
 {
     public bool IsStatic => true;
+    public bool IsExplicitImplementation => false;
 
     // NOTE: Override for covariant return type
     public override GlobalSymbol? GenericDefinition => null;
diff --git a/src/Draco.Compiler/Internal/Symbols/IMemberSymbol.cs b/src/Draco.Compiler/Internal/Symbols/IMemberSymbol.cs
index c3bb29097..9dede0337 100644
--- a/src/Draco.Compiler/Internal/Symbols/IMemberSymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/IMemberSymbol.cs
@@ -9,4 +9,9 @@ internal interface IMemberSymbol
     /// Specifying if given symbol is static.
     /// </summary>
     public bool IsStatic { get; }
+
+    /// <summary>
+    /// True if this member is an explicit implementation of an interface member.
+    /// </summary>
+    public bool IsExplicitImplementation { get; }
 }
diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataMethodSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataMethodSymbol.cs
index b4885d6fb..9213dfb52 100644
--- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataMethodSymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataMethodSymbol.cs
@@ -62,7 +62,14 @@ public override bool IsVirtual
                 || this.Override is not null;
         }
     }
+
     public override bool IsStatic => methodDefinition.Attributes.HasFlag(MethodAttributes.Static);
+
+    // TODO: Very hacky way of doing this
+    public override bool IsExplicitImplementation =>
+           this.Visibility == Api.Semantics.Visibility.Private
+        || this.Name.Contains('.');
+
     public override Api.Semantics.Visibility Visibility
     {
         get
diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataPropertySymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataPropertySymbol.cs
index d8e0abd93..0eb165fb2 100644
--- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataPropertySymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataPropertySymbol.cs
@@ -25,6 +25,9 @@ internal sealed class MetadataPropertySymbol(
     private FunctionSymbol? setter;
 
     public override bool IsStatic => (this.Getter ?? this.Setter)?.IsStatic ?? throw new InvalidOperationException();
+    public override bool IsExplicitImplementation => this.Getter?.IsExplicitImplementation
+                                                  ?? this.Setter?.IsExplicitImplementation
+                                                  ?? false;
 
     public override Api.Semantics.Visibility Visibility => (this.Getter ?? this.Setter)?.Visibility ?? throw new InvalidOperationException();
 
diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataTypeSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataTypeSymbol.cs
index 92a34f709..764fd626e 100644
--- a/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataTypeSymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/Metadata/MetadataTypeSymbol.cs
@@ -40,7 +40,7 @@ internal sealed class MetadataTypeSymbol(
 
     public override Symbol ContainingSymbol { get; } = containingSymbol;
 
-    public override bool IsValueType => this.BaseTypes.Contains(
+    public override bool IsValueType => this.IsEnumType || this.BaseTypes.Contains(
         this.Assembly.Compilation.WellKnownTypes.SystemValueType,
         SymbolEqualityComparer.Default);
 
@@ -48,6 +48,10 @@ internal sealed class MetadataTypeSymbol(
         this.Assembly.Compilation.WellKnownTypes.SystemDelegate,
         SymbolEqualityComparer.Default);
 
+    public override bool IsEnumType => this.BaseTypes.Contains(
+        this.Assembly.Compilation.WellKnownTypes.SystemEnum,
+        SymbolEqualityComparer.Default);
+
     public override bool IsInterface => typeDefinition.Attributes.HasFlag(TypeAttributes.Interface);
 
     public override bool IsAbstract => typeDefinition.Attributes.HasFlag(TypeAttributes.Abstract);
@@ -188,6 +192,13 @@ private ImmutableArray<Symbol> BuildMembers()
             if (propSym.Visibility == Api.Semantics.Visibility.Public) result.Add(propSym);
         }
 
+        // If this is an enum, inject == and != operators
+        if (this.IsEnumType)
+        {
+            var wellKnownTypes = this.Assembly.Compilation.WellKnownTypes;
+            result.AddRange(wellKnownTypes.GetEnumEqualityMembers(this));
+        }
+
         // Done
         return result.ToImmutable();
     }
diff --git a/src/Draco.Compiler/Internal/Symbols/Metadata/TypeProvider.cs b/src/Draco.Compiler/Internal/Symbols/Metadata/TypeProvider.cs
index 23fa996e9..241717352 100644
--- a/src/Draco.Compiler/Internal/Symbols/Metadata/TypeProvider.cs
+++ b/src/Draco.Compiler/Internal/Symbols/Metadata/TypeProvider.cs
@@ -9,6 +9,7 @@
 using Draco.Compiler.Api.Diagnostics;
 using Draco.Compiler.Internal.Binding;
 using Draco.Compiler.Internal.Symbols.Synthetized;
+using Draco.Compiler.Internal.Symbols.Synthetized.Array;
 
 namespace Draco.Compiler.Internal.Symbols.Metadata;
 
@@ -41,7 +42,7 @@ private readonly record struct CacheKey(
     private readonly ConcurrentDictionary<CacheKey, TypeSymbol> cache = new();
 
     public TypeSymbol GetArrayType(TypeSymbol elementType, ArrayShape shape) =>
-        new ArrayTypeSymbol(shape.Rank, this.WellKnownTypes.SystemInt32).GenericInstantiate(elementType);
+        new ArrayTypeSymbol(compilation, shape.Rank, this.WellKnownTypes.SystemInt32).GenericInstantiate(elementType);
     public TypeSymbol GetSZArrayType(TypeSymbol elementType) =>
         this.WellKnownTypes.ArrayType.GenericInstantiate(elementType);
     public TypeSymbol GetByReferenceType(TypeSymbol elementType) => UnknownType;
diff --git a/src/Draco.Compiler/Internal/Symbols/ModuleSymbol.cs b/src/Draco.Compiler/Internal/Symbols/ModuleSymbol.cs
index 15077cfa2..c8352c2ea 100644
--- a/src/Draco.Compiler/Internal/Symbols/ModuleSymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/ModuleSymbol.cs
@@ -15,6 +15,7 @@ internal abstract partial class ModuleSymbol : Symbol, IMemberSymbol
         : Visibility.Internal;
 
     public bool IsStatic => true;
+    public bool IsExplicitImplementation => false;
 
     public override void Accept(SymbolVisitor visitor) => visitor.VisitModule(this);
     public override TResult Accept<TResult>(SymbolVisitor<TResult> visitor) => visitor.VisitModule(this);
diff --git a/src/Draco.Compiler/Internal/Symbols/PropertySymbol.cs b/src/Draco.Compiler/Internal/Symbols/PropertySymbol.cs
index d580d4a11..1eb24f74c 100644
--- a/src/Draco.Compiler/Internal/Symbols/PropertySymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/PropertySymbol.cs
@@ -27,6 +27,7 @@ internal abstract class PropertySymbol : Symbol, ITypedSymbol, IMemberSymbol, IO
     /// </summary>
     public abstract bool IsIndexer { get; }
     public abstract bool IsStatic { get; }
+    public abstract bool IsExplicitImplementation { get; }
 
     public virtual Symbol? Override => null;
 
diff --git a/src/Draco.Compiler/Internal/Symbols/SymbolEqualityComparer.cs b/src/Draco.Compiler/Internal/Symbols/SymbolEqualityComparer.cs
index 2bae80d0d..21b7e1967 100644
--- a/src/Draco.Compiler/Internal/Symbols/SymbolEqualityComparer.cs
+++ b/src/Draco.Compiler/Internal/Symbols/SymbolEqualityComparer.cs
@@ -5,6 +5,7 @@
 using System.Runtime.CompilerServices;
 using Draco.Compiler.Internal.Symbols.Error;
 using Draco.Compiler.Internal.Symbols.Synthetized;
+using Draco.Compiler.Internal.Symbols.Synthetized.Array;
 
 namespace Draco.Compiler.Internal.Symbols;
 
diff --git a/src/Draco.Compiler/Internal/Symbols/Synthetized/ArrayConstructorSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Synthetized/Array/ArrayConstructorSymbol.cs
similarity index 95%
rename from src/Draco.Compiler/Internal/Symbols/Synthetized/ArrayConstructorSymbol.cs
rename to src/Draco.Compiler/Internal/Symbols/Synthetized/Array/ArrayConstructorSymbol.cs
index e749273e9..944fde8ef 100644
--- a/src/Draco.Compiler/Internal/Symbols/Synthetized/ArrayConstructorSymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/Synthetized/Array/ArrayConstructorSymbol.cs
@@ -3,7 +3,7 @@
 using System.Threading;
 using static Draco.Compiler.Internal.OptimizingIr.InstructionFactory;
 
-namespace Draco.Compiler.Internal.Symbols.Synthetized;
+namespace Draco.Compiler.Internal.Symbols.Synthetized.Array;
 
 /// <summary>
 /// A global constructor for arrays.
@@ -48,7 +48,7 @@ internal sealed class ArrayConstructorSymbol(ArrayTypeSymbol genericArrayType) :
 
     private ImmutableArray<ParameterSymbol> BuildParameters() => this.Rank switch
     {
-        1 => [new SynthetizedParameterSymbol(this, "capacity", genericArrayType.IndexType) as ParameterSymbol],
+        1 => [new SynthetizedParameterSymbol(this, "capacity", genericArrayType.IndexType)],
         int n => Enumerable
             .Range(1, n)
             .Select(i => new SynthetizedParameterSymbol(this, $"capacity{i}", genericArrayType.IndexType) as ParameterSymbol)
diff --git a/src/Draco.Compiler/Internal/Symbols/Synthetized/ArrayIndexPropertySymbol.cs b/src/Draco.Compiler/Internal/Symbols/Synthetized/Array/ArrayIndexPropertySymbol.cs
similarity index 96%
rename from src/Draco.Compiler/Internal/Symbols/Synthetized/ArrayIndexPropertySymbol.cs
rename to src/Draco.Compiler/Internal/Symbols/Synthetized/Array/ArrayIndexPropertySymbol.cs
index a205fb647..ce6947a21 100644
--- a/src/Draco.Compiler/Internal/Symbols/Synthetized/ArrayIndexPropertySymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/Synthetized/Array/ArrayIndexPropertySymbol.cs
@@ -1,7 +1,7 @@
 using System.Collections.Immutable;
 using System.Linq;
 
-namespace Draco.Compiler.Internal.Symbols.Synthetized;
+namespace Draco.Compiler.Internal.Symbols.Synthetized.Array;
 
 /// <summary>
 /// The indexer property of arrays.
@@ -15,6 +15,7 @@ internal sealed class ArrayIndexPropertySymbol : PropertySymbol
 
     public override bool IsIndexer => true;
     public override bool IsStatic => false;
+    public override bool IsExplicitImplementation => false;
 
     public ArrayIndexPropertySymbol(ArrayTypeSymbol containingSymbol)
     {
diff --git a/src/Draco.Compiler/Internal/Symbols/Synthetized/Array/ArrayTypeSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Synthetized/Array/ArrayTypeSymbol.cs
new file mode 100644
index 000000000..47924ec59
--- /dev/null
+++ b/src/Draco.Compiler/Internal/Symbols/Synthetized/Array/ArrayTypeSymbol.cs
@@ -0,0 +1,89 @@
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using Draco.Compiler.Api;
+
+namespace Draco.Compiler.Internal.Symbols.Synthetized.Array;
+
+/// <summary>
+/// An array modeled as generics.
+/// </summary>
+internal sealed class ArrayTypeSymbol : TypeSymbol
+{
+    /// <summary>
+    /// The element type this array stores.
+    /// </summary>
+    public TypeParameterSymbol ElementType { get; }
+
+    /// <summary>
+    /// The index type this array can be indexed with.
+    /// </summary>
+    public TypeSymbol IndexType { get; }
+
+    /// <summary>
+    /// The rank of the array (number of dimensions).
+    /// </summary>
+    public int Rank { get; }
+
+    public override bool IsArrayType => true;
+
+    public override Compilation DeclaringCompilation { get; }
+
+    public override ImmutableArray<TypeSymbol> ImmediateBaseTypes =>
+        InterlockedUtils.InitializeDefault(ref this.immediateBaseTypes, this.BuildImmediateBaseTypes);
+    private ImmutableArray<TypeSymbol> immediateBaseTypes;
+
+    public override string Name => this.Rank switch
+    {
+        1 => "Array",
+        int n => $"Array{n}D",
+    };
+
+    public override ImmutableArray<TypeParameterSymbol> GenericParameters => [this.ElementType];
+
+    public override IEnumerable<Symbol> DefinedMembers => InterlockedUtils.InitializeDefault(ref this.definedMembers, this.BuildDefinedMembers);
+    private ImmutableArray<Symbol> definedMembers;
+
+    public ArrayTypeSymbol(Compilation compilation, int rank, TypeSymbol indexType)
+    {
+        this.DeclaringCompilation = compilation;
+        this.ElementType = new SynthetizedTypeParameterSymbol(this, "T");
+        this.Rank = rank;
+        this.IndexType = indexType;
+    }
+
+    public TypeSymbol GenericInstantiate(TypeSymbol elementType) =>
+        this.GenericInstantiate(containingSymbol: null, ImmutableArray.Create(elementType));
+
+    public override string ToString() => $"{this.Name}{this.GenericsToString()}";
+
+    private ImmutableArray<TypeSymbol> BuildImmediateBaseTypes()
+    {
+        var wellKnownTypes = this.DeclaringCompilation.WellKnownTypes;
+
+        // We need to implement System.Array, IList, IReadOnlyList
+        return [
+            wellKnownTypes.SystemArray,
+            wellKnownTypes.SystemCollectionsGenericIList_1.GenericInstantiate(this.ContainingSymbol, [this.ElementType]),
+            wellKnownTypes.SystemCollectionsGenericIReadOnlyList_1.GenericInstantiate(this.ContainingSymbol, [this.ElementType])];
+    }
+
+    private ImmutableArray<Symbol> BuildDefinedMembers()
+    {
+        if (this.Rank == 1)
+        {
+            // We need to re-add all members that should not be hidden by the base types
+            // IList will provide indexing
+            var iEnumerableBase = this.BaseTypes.First(b => b.Name == "IEnumerable" && b.IsGenericInstance);
+            var iListBase = this.BaseTypes.First(b => b.Name == "IList" && b.IsGenericInstance);
+            return iEnumerableBase.DefinedMembers
+                .Concat(iListBase.DefinedMembers)
+                .ToImmutableArray();
+        }
+        else
+        {
+            // We just provide indexing
+            return [new ArrayIndexPropertySymbol(this)];
+        }
+    }
+}
diff --git a/src/Draco.Compiler/Internal/Symbols/Synthetized/ArrayLengthPropertySymbol.cs b/src/Draco.Compiler/Internal/Symbols/Synthetized/ArrayLengthPropertySymbol.cs
deleted file mode 100644
index 13d0d8f9c..000000000
--- a/src/Draco.Compiler/Internal/Symbols/Synthetized/ArrayLengthPropertySymbol.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System.Collections.Immutable;
-
-namespace Draco.Compiler.Internal.Symbols.Synthetized;
-
-/// <summary>
-/// The length property of an array.
-/// </summary>
-internal sealed class ArrayLengthPropertySymbol : PropertySymbol
-{
-    public override string Name => "Length";
-
-    public override FunctionSymbol Getter { get; }
-    public override FunctionSymbol? Setter => null;
-
-    public override TypeSymbol Type => this.ContainingSymbol.IndexType;
-    public override ArrayTypeSymbol ContainingSymbol { get; }
-
-    public override bool IsIndexer => false;
-    public override bool IsStatic => false;
-
-    public ArrayLengthPropertySymbol(ArrayTypeSymbol containingSymbol)
-    {
-        this.ContainingSymbol = containingSymbol;
-        this.Getter = new ArrayLengthGetSymbol(containingSymbol, this);
-    }
-}
-
-/// <summary>
-/// The getter of array Length.
-/// </summary>
-internal sealed class ArrayLengthGetSymbol(
-    ArrayTypeSymbol containingSymbol,
-    PropertySymbol propertySymbol) : FunctionSymbol, IPropertyAccessorSymbol
-{
-    public override ImmutableArray<ParameterSymbol> Parameters => [];
-    public override TypeSymbol ReturnType => this.ContainingSymbol.IndexType;
-    public override bool IsStatic => false;
-
-    public override ArrayTypeSymbol ContainingSymbol { get; } = containingSymbol;
-    public PropertySymbol Property { get; } = propertySymbol;
-}
diff --git a/src/Draco.Compiler/Internal/Symbols/Synthetized/ArrayTypeSymbol.cs b/src/Draco.Compiler/Internal/Symbols/Synthetized/ArrayTypeSymbol.cs
deleted file mode 100644
index 7af265330..000000000
--- a/src/Draco.Compiler/Internal/Symbols/Synthetized/ArrayTypeSymbol.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using System.Collections.Generic;
-using System.Collections.Immutable;
-
-namespace Draco.Compiler.Internal.Symbols.Synthetized;
-
-/// <summary>
-/// An array modeled as generics.
-/// </summary>
-internal sealed class ArrayTypeSymbol : TypeSymbol
-{
-    /// <summary>
-    /// The element type this array stores.
-    /// </summary>
-    public TypeParameterSymbol ElementType { get; }
-
-    /// <summary>
-    /// The index type this array can be indexed with.
-    /// </summary>
-    public TypeSymbol IndexType { get; }
-
-    /// <summary>
-    /// The rank of the array (number of dimensions).
-    /// </summary>
-    public int Rank { get; }
-
-    public override string Name => this.Rank switch
-    {
-        1 => "Array",
-        int n => $"Array{n}D",
-    };
-
-    public override ImmutableArray<TypeParameterSymbol> GenericParameters => [this.ElementType];
-
-    public override IEnumerable<Symbol> DefinedMembers =>
-    [
-        new ArrayLengthPropertySymbol(this) as Symbol,
-        new ArrayIndexPropertySymbol(this),
-    ];
-
-    public ArrayTypeSymbol(int rank, TypeSymbol indexType)
-    {
-        this.ElementType = new SynthetizedTypeParameterSymbol(this, "T");
-        this.Rank = rank;
-        this.IndexType = indexType;
-    }
-
-    public TypeSymbol GenericInstantiate(TypeSymbol elementType) =>
-        this.GenericInstantiate(containingSymbol: null, ImmutableArray.Create(elementType));
-
-    public override string ToString() => $"{this.Name}{this.GenericsToString()}";
-}
diff --git a/src/Draco.Compiler/Internal/Symbols/TypeSymbol.cs b/src/Draco.Compiler/Internal/Symbols/TypeSymbol.cs
index 2183bcc47..279865af4 100644
--- a/src/Draco.Compiler/Internal/Symbols/TypeSymbol.cs
+++ b/src/Draco.Compiler/Internal/Symbols/TypeSymbol.cs
@@ -31,6 +31,16 @@ internal abstract partial class TypeSymbol : Symbol, IMemberSymbol
     /// </summary>
     public virtual bool IsDelegateType => false;
 
+    /// <summary>
+    /// True, if this type is an enum type.
+    /// </summary>
+    public virtual bool IsEnumType => false;
+
+    /// <summary>
+    /// True. if this is a native .NET array type.
+    /// </summary>
+    public virtual bool IsArrayType => false;
+
     /// <summary>
     /// True, if this type is an interface.
     /// </summary>
@@ -100,6 +110,7 @@ internal abstract partial class TypeSymbol : Symbol, IMemberSymbol
     public override TypeSymbol? GenericDefinition => null;
 
     public bool IsStatic => true;
+    public bool IsExplicitImplementation => false;
 
     /// <summary>
     /// The invokable function, if this is a delegate type.
diff --git a/src/Draco.Compiler/Internal/Symbols/WellKnownTypes.cs b/src/Draco.Compiler/Internal/Symbols/WellKnownTypes.cs
index fae67bfba..6eed87a1f 100644
--- a/src/Draco.Compiler/Internal/Symbols/WellKnownTypes.cs
+++ b/src/Draco.Compiler/Internal/Symbols/WellKnownTypes.cs
@@ -12,6 +12,7 @@
 using Draco.Compiler.Internal.Symbols.Generic;
 using Draco.Compiler.Internal.Symbols.Metadata;
 using Draco.Compiler.Internal.Symbols.Synthetized;
+using Draco.Compiler.Internal.Symbols.Synthetized.Array;
 using static Draco.Compiler.Internal.OptimizingIr.InstructionFactory;
 
 namespace Draco.Compiler.Internal.Symbols;
@@ -64,7 +65,7 @@ private IEnumerable<Symbol> GenerateWellKnownTypes()
         for (var i = 2; i <= 8; ++i)
         {
             // Type
-            var arrayType = new ArrayTypeSymbol(i, this.SystemInt32);
+            var arrayType = new ArrayTypeSymbol(compilation, i, this.SystemInt32);
             yield return arrayType;
             // Ctor
             yield return new ArrayConstructorSymbol(arrayType);
@@ -170,12 +171,28 @@ private static SynthetizedAliasSymbol Alias(string name, TypeSymbol type) =>
     public TypeSymbol InstantiateArray(TypeSymbol elementType, int rank = 1) => rank switch
     {
         1 => this.ArrayType.GenericInstantiate(elementType),
-        int n => new ArrayTypeSymbol(n, this.SystemInt32).GenericInstantiate(elementType),
+        int n => new ArrayTypeSymbol(compilation, n, this.SystemInt32).GenericInstantiate(elementType),
     };
 
     #endregion
 
-    public ArrayTypeSymbol ArrayType => LazyInitializer.EnsureInitialized(ref this.array, () => new(1, this.SystemInt32));
+    #region Additives/Mixins for types
+    /// <summary>
+    /// Returns all the equality operator members for an enum type.
+    /// </summary>
+    /// <param name="type">The enum type.</param>
+    /// <returns>The equality operator members.</returns>
+    public IEnumerable<Symbol> GetEnumEqualityMembers(TypeSymbol type)
+    {
+        if (!type.IsEnumType) throw new ArgumentException("the type must be an enum type", nameof(type));
+
+        // == and !=
+        yield return this.Comparison(TokenKind.Equal, type, type, FromAllocating(this.CodegenEqual));
+        yield return this.Comparison(TokenKind.NotEqual, type, type, FromAllocating(this.CodegenNotEqual));
+    }
+    #endregion
+
+    public ArrayTypeSymbol ArrayType => LazyInitializer.EnsureInitialized(ref this.array, () => new(compilation, 1, this.SystemInt32));
     private ArrayTypeSymbol? array;
 
     public ArrayConstructorSymbol ArrayCtor => LazyInitializer.EnsureInitialized(ref this.arrayCtor, () => new(this.ArrayType));
diff --git a/src/Draco.Compiler/Internal/Symbols/WellKnownTypes.xml b/src/Draco.Compiler/Internal/Symbols/WellKnownTypes.xml
index 5a17daf47..f554953e9 100644
--- a/src/Draco.Compiler/Internal/Symbols/WellKnownTypes.xml
+++ b/src/Draco.Compiler/Internal/Symbols/WellKnownTypes.xml
@@ -29,7 +29,11 @@
 
   <Type Name="System.Type" Assembly="System.Runtime" />
   <Type Name="System.Array" Assembly="System.Runtime" />
+  <Type Name="System.Enum" Assembly="System.Runtime" />
   <Type Name="System.ValueType" Assembly="System.Runtime" />
   <Type Name="System.Delegate" Assembly="System.Runtime" />
 
+  <Type Name="System.Collections.Generic.IList`1" Assembly="System.Runtime" />
+  <Type Name="System.Collections.Generic.IReadOnlyList`1" Assembly="System.Runtime" />
+
 </WellKnownTypes>
diff --git a/src/Draco.LanguageServer/DracoLanguageServer.cs b/src/Draco.LanguageServer/DracoLanguageServer.cs
index 5fc45dd38..03184ecd3 100644
--- a/src/Draco.LanguageServer/DracoLanguageServer.cs
+++ b/src/Draco.LanguageServer/DracoLanguageServer.cs
@@ -93,7 +93,7 @@ private async Task CreateCompilation()
             syntaxTrees: syntaxTrees,
 
             metadataReferences: designTimeBuild.References
-                .Select(r => MetadataReference.FromPeStream(r.OpenRead()))
+                .Select(r => MetadataReference.FromFile(r.FullName))
                 .ToImmutableArray(),
             rootModulePath: rootPath);
     }
diff --git a/src/Draco.ProjectSystem/Project.cs b/src/Draco.ProjectSystem/Project.cs
index 2231511a2..766bc1a6f 100644
--- a/src/Draco.ProjectSystem/Project.cs
+++ b/src/Draco.ProjectSystem/Project.cs
@@ -3,7 +3,6 @@
 using System.IO;
 using System.Linq;
 using Microsoft.Build.Evaluation;
-using Microsoft.Build.Framework;
 using MSBuildProject = Microsoft.Build.Evaluation.Project;
 using MSBuildProjectInstance = Microsoft.Build.Execution.ProjectInstance;
 
diff --git a/src/Draco.Repl/ReplPromptCallbacks.cs b/src/Draco.Repl/ReplPromptCallbacks.cs
index 4b331ddc3..edc5135e9 100644
--- a/src/Draco.Repl/ReplPromptCallbacks.cs
+++ b/src/Draco.Repl/ReplPromptCallbacks.cs
@@ -7,7 +7,6 @@
 using Draco.Compiler.Api.Scripting;
 using Draco.Compiler.Api.Syntax;
 using PrettyPrompt;
-using PrettyPrompt.Completion;
 using PrettyPrompt.Consoles;
 using PrettyPrompt.Documents;
 using PrettyPrompt.Highlighting;
diff --git a/src/Draco.SourceGeneration/Templates/WellKnownTypes.sbncs b/src/Draco.SourceGeneration/Templates/WellKnownTypes.sbncs
index 2ba6ffccb..dc1bcd10d 100644
--- a/src/Draco.SourceGeneration/Templates/WellKnownTypes.sbncs
+++ b/src/Draco.SourceGeneration/Templates/WellKnownTypes.sbncs
@@ -6,7 +6,9 @@ using Draco.Compiler.Internal.Symbols.Synthetized;
 {{include 'Utils.sbncs'}}
 
 {{func nameify(name)}}
-    {{ret string.replace(name, '.', '')}}
+    {{$result = string.replace(name, '.', '')}}
+    {{$result = string.replace($result, '`', '_')}}
+    {{ret $result}}
 {{end}}
 
 #nullable enable