Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type instantiation in result function types when using constructors as functions #1467

Closed
tvdstorm opened this issue Dec 23, 2020 · 7 comments

Comments

@tvdstorm
Copy link
Member

Let's say we have the following module:

module Curry

int sum(int x, int y) = x + y;

data Expr
  = add(Expr lhs, Expr rhs)
  | lit(int x);

&S(&U) curry(&S(&T, &U) f, &T t)
  = &S(&U u) { return f(t, u); }; 

At the prompt I can do f = curry(sum, 1), which results in:

&S(&U): function(...)

The return type, should be int(int) I guess, but calling f(2) correctly evaluates to 3.

But calling curry on a constructor, leads to an exception:

rascal>g = curry(add, lit(1));
&S (&U): function(|project://TwoStones/src/Curry.rsc|(139,28,<11,4>,<11,32>))
rascal>g(lit(2))
io.usethesource.vallang.exceptions.IllegalOperationException: Operation getTypeParameters not allowed on value
(internal error)
        at $root$(|main://$root$|)

io.usethesource.vallang.exceptions.IllegalOperationException: Operation getTypeParameters not allowed on value
        at io.usethesource.vallang.type.Type.getTypeParameters(Type.java:595)
        at io.usethesource.vallang.type.ParameterType.getTypeParameters(ParameterType.java:92)
        at io.usethesource.vallang.type.AbstractDataType.match(AbstractDataType.java:418)
        at io.usethesource.vallang.type.TupleType.match(TupleType.java:414)
        at org.rascalmpl.interpreter.result.ConstructorFunction.call(ConstructorFunction.java:230)
        at org.rascalmpl.semantics.dynamic.Expression$CallOrTree.interpret(Expression.java:536)
        at org.rascalmpl.semantics.dynamic.Statement$Expression.interpret(Statement.java:365)
        at org.rascalmpl.semantics.dynamic.Statement$Return.interpret(Statement.java:782)
        at org.rascalmpl.interpreter.result.RascalFunction.runBody(RascalFunction.java:388)
        at org.rascalmpl.interpreter.result.RascalFunction.call(RascalFunction.java:329)
        at org.rascalmpl.semantics.dynamic.Expression$CallOrTree.interpret(Expression.java:536)
        at org.rascalmpl.semantics.dynamic.Command$Expression.interpret(Command.java:61)
        at org.rascalmpl.interpreter.Evaluator.eval(Evaluator.java:1157)
        at org.rascalmpl.interpreter.Evaluator.eval(Evaluator.java:1027)
        at org.rascalmpl.interpreter.Evaluator.eval(Evaluator.java:982)
        at org.rascalmpl.repl.RascalInterpreterREPL.evalStatement(RascalInterpreterREPL.java:136)
        at org.rascalmpl.eclipse.repl.RascalTerminalConnector$2.evalStatement(RascalTerminalConnector.java:342)
        at org.rascalmpl.repl.BaseRascalREPL.handleInput(BaseRascalREPL.java:108)
        at org.rascalmpl.eclipse.repl.RascalTerminalConnector$2.handleInput(RascalTerminalConnector.java:297)
        at org.rascalmpl.repl.BaseREPL.handleInput(BaseREPL.java:172)
        at org.rascalmpl.repl.BaseREPL.run(BaseREPL.java:335)

So I think there are two problems, but it's unclear to me if and if so, how, they are related:

  • unbound type variables in generic function results
  • constructors are not treated the same as functions everywhere.
@tvdstorm
Copy link
Member Author

void main() {
  int(int) f = curry(sum, 1);
  
  Expr(Expr) g = curry(add, lit(1));
  
  println(f(2));
  
  println(g(lit(2))); 
}

This passed the compiler's type checker.

The interpreter, however, complains when I try to run it:

rascal>main()
|project://TwoStones/src/Curry.rsc|(210,17,<16,11>,<16,28>): Expected int (int), but got &S (&U)
Advice: |http://tutor.rascal-mpl.org/Errors/Static/UnexpectedType/UnexpectedType.html|
ok

@jurgenvinju
Copy link
Member

Interesting bug. Will have a look in January; can you manage a workaround in the mean time?

@jurgenvinju
Copy link
Member

The bug is caused by this line right here:

return (AbstractFunction) value;

The code correctly returns the function as a result (this is a quick implementation), but in case of an instantiated abstract function, the type will not be instantiated in this case resulting in incorrect information loss.

@jurgenvinju
Copy link
Member

io.usethesource.vallang.exceptions.IllegalOperationException: Operation getTypeParameters not allowed on value still happens

@jurgenvinju
Copy link
Member

@tvdstorm
Copy link
Member Author

More fun: self-applying curry doesn't terminate.

curry(curry, sum)

@jurgenvinju
Copy link
Member

The current state is that self-application of curry is not possible yet. The root cause is a very basic (and wrong) assumption in the code of the interpreter: for functions (closures and/or generic or otherwise) the static type is equal to their dynamic type. This is because each function instance extends Result<IValue> (which tuples a static type with a dynamic value), as well as implements IFunction and ICalleableValue which are dynamic value implementations. Both Result and IValue implement getType() but their intended semantics is quite different. Fixing this entails a significant rewrite of the function calling semantics in the interpreter.

jurgenvinju added a commit that referenced this issue Jan 7, 2021
…are downstream changes to work with the new function type from vallang. All tests succeed but the self-application of curry from issue #1468 and issue #1467
jurgenvinju added a commit that referenced this issue Jan 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants