Repository: elm-tooling/elm-language-server
Pull request #389 (2020-12-06 07:51:44)

Bug fixes
Fixes include:
- Many wrong redefinition errors
- Inference of function with unit_expr as param
- Fixed inference of type classes with suffixes
- Fixed definition when union constructor is used in bin_op_expr


Patch:
diff --git a/src/util/types/expressionTree.ts b/src/util/types/expressionTree.ts
index 6e676d2..5d33490 100644
--- a/src/util/types/expressionTree.ts
+++ b/src/util/types/expressionTree.ts
@@ -395,7 +395,7 @@ export function mapSyntaxNodeToExpression(
         const functionDeclarationLeft = node as EFunctionDeclarationLeft;
         functionDeclarationLeft.nodeType = "FunctionDeclarationLeft";
         functionDeclarationLeft.params = node.namedChildren
-          .filter((n) => n.type.includes("pattern"))
+          .filter((n) => n.type.includes("pattern") || n.type === "unit_expr")
           ?.map(mapSyntaxNodeToExpression)
           .filter(
             Utils.notUndefined.bind(mapSyntaxNodeToExpression),
diff --git a/src/util/types/typeChecker.ts b/src/util/types/typeChecker.ts
index 3a74109..a5e8f4f 100644
--- a/src/util/types/typeChecker.ts
+++ b/src/util/types/typeChecker.ts
@@ -464,9 +464,10 @@ export function createTypeChecker(workspace: IElmWorkspace): TypeChecker {
         upperCaseQid.parent?.type === "exposed_type";
       const isConstructorUsage = upperCaseQid.parent?.type === "value_expr";
       const isFunctionUsage =
-        upperCaseQid.parent?.parent?.type === "function_call_expr" &&
-        upperCaseQid.parent.parent.childForFieldName("target")?.id ===
-          upperCaseQid.parent.id;
+        (upperCaseQid.parent?.parent?.type === "function_call_expr" &&
+          upperCaseQid.parent.parent.childForFieldName("target")?.id ===
+            upperCaseQid.parent.id) ||
+        upperCaseQid.parent?.parent?.type === "bin_op_expr";
 
       const definitionNode = rootSymbols?.get(upperCaseQidText, (symbol) =>
         isTypeUsage
diff --git a/src/util/types/typeInference.ts b/src/util/types/typeInference.ts
index 51b45ed..190adbe 100644
--- a/src/util/types/typeInference.ts
+++ b/src/util/types/typeInference.ts
@@ -345,12 +345,16 @@ function getParentPatternDeclaration(
 }
 
 export function getTypeclassName(type: TVar): string | undefined {
-  switch (type.name) {
-    case "number":
-    case "appendable":
-    case "comparable":
-    case "compappend":
-      return type.name;
+  if (type.name.length < 6) {
+    return;
+  } else if (type.name.startsWith("number")) {
+    return "number";
+  } else if (type.name.startsWith("appendable")) {
+    return "appendable";
+  } else if (type.name.startsWith("comparable")) {
+    return "comparable";
+  } else if (type.name.startsWith("compappend")) {
+    return "compappend";
   }
 }
 
@@ -553,7 +557,8 @@ export class InferenceScope {
     cancellationToken?: ICancellationToken,
   ): InferenceResult {
     const nonShadowableNames =
-      program.getSourceFile(uri)?.nonShadowableNames ?? new Set<string>();
+      new Set(program.getSourceFile(uri)?.nonShadowableNames) ??
+      new Set<string>();
 
     const setter = (): InferenceResult =>
       new InferenceScope(


Test patch:
diff --git a/test/definitionProviderTests/importDefinition.test.ts b/test/definitionProviderTests/importDefinition.test.ts
index 9693ba3..1e37f4a 100644
--- a/test/definitionProviderTests/importDefinition.test.ts
+++ b/test/definitionProviderTests/importDefinition.test.ts
@@ -532,6 +532,27 @@ import Module.Model as Model
 
 type Model = String
 --X
+`;
+    await testBase.testDefinition(source);
+  });
+
+  it(`test union constructor resolves when it is used in bin op expr`, async () => {
+    const source = `
+--@ main.elm
+import App exposing (..)
+
+type alias Expression =
+    App.Expression
+    
+func : Expression
+func = "" >> Expression
+               --^App.elm
+
+--@ App.elm
+module App exposing (..)
+
+type Expression = Expression
+                    --X
 `;
     await testBase.testDefinition(source);
   });
diff --git a/test/diagnosticTests/elmDiagnostics.test.ts b/test/diagnosticTests/elmDiagnostics.test.ts
index 78faef8..d71f91d 100644
--- a/test/diagnosticTests/elmDiagnostics.test.ts
+++ b/test/diagnosticTests/elmDiagnostics.test.ts
@@ -177,4 +177,33 @@ field { field } =
       { message: Diagnostics.Redefinition, args: ["field"] },
     ]);
   });
+
+  test("Type class used with a suffix", async () => {
+    const source = `
+--@ Test.elm
+module Test exposing (..)
+
+field : number1
+field =
+    4
+  `;
+    await testTypeInference(basicsSources + source, []);
+  });
+
+  test("unit expr as a function param", async () => {
+    const source = `
+--@ Test.elm
+module Test exposing (..)
+
+field : () -> Int
+field =
+    let
+        func () =
+            4
+
+    in
+    func
+  `;
+    await testTypeInference(basicsSources + source, []);
+  });
 });
diff --git a/test/diagnostics.ts b/test/diagnostics.ts
index 2659038..cbe9b49 100644
--- a/test/diagnostics.ts
+++ b/test/diagnostics.ts
@@ -96,7 +96,7 @@ export async function runDiagnosticTests(uri: string): Promise<void> {
     elmWorkspace = undefined!;
   } catch (e) {
     console.log(e);
-    failed.push(uri);
+    failed.push(path.basename(uri));
     // process.exitCode = 1;
   }
 }
@@ -130,9 +130,12 @@ const parsingFailures = [
   "terezka/charts", // Let expr on the same line
   "zwilias/json-decode-exploration", // Weird parsing error in mgold/elm-nonempty-list
 ];
-const compilerFailures = ["pablohirafuji/elm-qrcode", "rtfeldman/elm-css"];
+const compilerFailures = ["mdgriffith/elm-ui", "frandibar/elm-bootstrap"];
 
-const unknownFailures = ["Chadtech/elm-css-grid"];
+const otherFailures = [
+  "Chadtech/elm-vector", // Too big
+  "arowM/html-extra", // Advanced module resolution bug
+];
 
 let completed: string[] = [];
 
@@ -150,9 +153,9 @@ const filteredLibs = libsToParse
     (lib) =>
       !lib.startsWith("elm/") &&
       !lib.startsWith("elm-explorations/") &&
-      !unknownFailures.includes(lib) &&
+      !otherFailures.includes(lib) &&
       // !parsingFailures.includes(lib) &&
-      // !compilerFailures.includes(lib) &&
+      !compilerFailures.includes(lib) &&
       !completed.includes(path.join(__dirname, "../", `examples-full/${lib}`)),
   );