usethesource / rascal

The implementation of the Rascal meta-programming language (including interpreter, type checker, parser generator, compiler and JVM based run-time system)
http://www.rascal-mpl.org
Other
406 stars 78 forks source link

Unclear type error message when accidentally iterating with `<-` instead of matching with `:=` #1748

Open olijf opened 1 year ago

olijf commented 1 year ago

Why is this a problem?

rascal>[abstract | <set[M3] model, set[Declaration] abstract> <- createM3sAndAstsFromFiles({ location }), method(model)];
|std:///lang/java/m3/Core.rsc|(3653,5,<85,179>,<85,184>): Expected tuple[set[M3],set[Declaration]], but got tuple[set[M3],set[Declaration]]

But this works:

rascal>[nummer | <basis, nummer> <- [<b, n> | b <- {x | x <- [1..10]}, n <- {x*x | x <- [1..10]}], basis % 2 == 0]
list[int]: [16,64,1,9,81,4,49,36,25,16,64,1,9,81,4,49,36,25,16,64,1,9,81,4,49,36,25,16,64,1,9,81,4,49,36,25]
jurgenvinju commented 1 year ago

Nice parallel!

Expected tuple[set[M3],set[Declaration]], but got tuple[set[M3],set[Declaration]]

The two types are identical as far as we can see here, so this does not make any sense.. yet.

So, let's investigate the "as far as we can see" bit. M3 and Declaration are two names here. Names can be ambiguous. For example: Declaration is both a data type and an alias or a syntax or layout or lexical or keyword name. From the function createM3sAndAstsFromFiles both types are defined as data types, but in the current module it can be there is another definition visible. Is that the case?

What does method(model) do and where is it defined?

I'll try to trigger the same behavior in the meantime.

jurgenvinju commented 1 year ago

Ok. I reproduced the issue. It is a case of a broken error message. What is going wrong here is matching against the top element using := versus matching against each element of a container using <-.

rascal><set[M3] model, set[Declaration] abstract> <- createM3sAndAstsFromFiles({|home:///git/vallang/src/main/java/io/usethesource/vallang/IString.java|})
|std:///lang/java/m3/Core.rsc|(3653,5,<85,179>,<85,184>): Expected tuple[set[M3],set[Declaration]], but got tuple[set[M3],set[Declaration]]
Advice: |https://www.rascal-mpl.org/docs/Rascal/Errors/CompileTimeErrors/UnexpectedType/UnexpectedType.html|
ok
rascal><set[M3] model, set[Declaration] abstract> := createM3sAndAstsFromFiles({|home:///git/vallang/src/main/java/io/usethesource/vallang/IString.java|})
bool: true
jurgenvinju commented 1 year ago

The second example is working because [<b, n> | b <- {x | x <- [1..10]}, n <- {x*x | x <- [1..10]}] is a list of tuples, which can each be matched by the tuple pattern, while createM3sAndAstsFromFiles creates a single tuple, for which <- will generate each element (M3 and AST), and then <- will match a tuple against the M3 and a tuple against the AST which is guaranteed to always fail. That's why there is an error message, but it must be much more clear.

olijf commented 1 year ago

So how would I approach this? I want a filtered list of Declarations by filtering all the methods in the m3 model using https://www.rascal-mpl.org/docs/Library/lang/java/m3/Core/#lang-java-m3-Core-methods which I can then use to calculate the complexity on. I tried assigning the output of createM3sAndAstsFromFiles but it gives the same error if i filter the list.

jurgenvinju commented 1 year ago

So you want all the methods from all the ASTs which are present in the M3 model?

<set[M3] model, set[Declaration] cus> = createM3sAndAstsFromFiles({ location });
allMethods = methods(model);

allMethodASTs = {  d |  / Declaration d := cus, d.decl?, d.decl in allMethods };

It is not strictly necessary to filter with the methods(model) set. You can also pattern match all the methods. Using /method(_, _ ...) := tu.

Watch out for abstract methods and interfaces. Some declarations look like methods, but they are really only signature declarations and they have no bodies.