Skip to content

Conversation

@b-studios
Copy link
Collaborator

No description provided.

List(
Definition.Let(orig, origTpe, transform(binding)),
Definition.Let(id, transform(tpe), coerce(ValueVar(orig, origTpe))))
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you need to translate one let into two here?

Copy link
Contributor

@marzipankaiser marzipankaiser May 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the coerce expects a Pure [1] expression but the binding is not.
So we introduce two bindings:

  • One for the "original" value
  • One for the boxed/unboxed value

AFAICT there is no binding construct for expressions, is there?
Alterantively, we could use something like Run(Let(orig, origTpe, transform(binding), coerce(...))).

[1]: This is mostly to cut down on cases, and since we will use the value as a parameter to Make anyway (so an intermediate value is needed).

Comment on lines +194 to +199
case v @ source.ValDef(id, tpe, binding) if pureOrIO(binding) =>
val transformed = Run(transform(binding))
val transformedTpe = v.symbol.tpe match {
case Some(tpe) => transform(tpe)
case None => transformed.tpe
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pattern shows up quite often, how can we simplify?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like foo(v.symbol.tpe, transformed.tpe) might be possible, equivalent to a
v.symbol.tpe.map(transform).getOrElse(transformed.tpe).
Though I'm not sure it's worth it.

I am unsure if we can abstract over more easily since the type of binding/transformed is different in most cases (Stmt for val, Expr for let). - This also means that the call to transform (on the binding) is a different one.

@marzipankaiser marzipankaiser changed the title Add explicit type annotation to Val Add explicit type annotation to Val, Let May 22, 2024
@b-studios
Copy link
Collaborator Author

Sadly, this still doesn't solve the LLVM issue for me on #449

Even when merging this PR here I still get

opt: ./out/strings.ll:13764:9: error: multiple definition of local value named 'tmp31441_4389'
        %tmp31441_4389 = load %Pos, ptr %tmp31441_4389p_4562
        ^

on

run --backend llvm examples/stdlib/string/strings.effekt

@marzipankaiser
Copy link
Contributor

@phischu @b-studios
The next minified example is:

interface MyException {
  def myraise(): Nothing
}

def myDefault[T]{d: => T}{body: => T / MyException} = try { body() } with MyException {
  def myraise() = d()
}

def main() = {
  try {
    myDefault { val t = do myraise(); t }{ 0 };
    ()
  } with MyException {
    def myraise() = ()
  }
}

@marzipankaiser
Copy link
Contributor

I think the problem is here:

instantiate(calleeT, targs).call(calleeT, vargs map transform, bargs map transform)

instantiate(b, targs).callDirect(b, vargs map transform, bargs map transform)

case Pure.PureApp(b, targs, vargs) => instantiate(b, targs).callPure(b, vargs map transform)

Where now, we also need to check the paramaters and potentially box/unbox those.
This is only due to subtyping, which was added recently (for parametric polymorphism, representations of ValueTypes match up after instantiation, and BlockTypes do, too - since we do not instantiate implicitly! - this is however no longer true for subtyping).

This will:
- Potentially incur double coercions for arguments
- Probably not work in some cases, as we do not track the return type

But this does fix the bugs we are currently running into.

Note: In the future, a more complete rewrite is needed, as it was
written with parametric polymorphism in mind and is now used for
subtyping. This means the assumption that casts *only* need to happen
at instantiation sites (i.e. call sites) is broken.
@marzipankaiser
Copy link
Contributor

@b-studios Now, the StdlibLLVMTests pass for me (when merging fix/boxing-nothing with refactor/stdlib).

@marzipankaiser marzipankaiser changed the title Add explicit type annotation to Val, Let Fix boxing of Nothing / Add explicit type annotation to Val, Let May 23, 2024
@b-studios
Copy link
Collaborator Author

Can you add the new minified example to the hotfix?

@b-studios
Copy link
Collaborator Author

This suggests to me that using PolymorphismBoxing to also deal with Nothing and Any was maybe not a good idea.

@b-studios
Copy link
Collaborator Author

I merged it into #449 and it indeed resolves the problems with the LLVM backend there. Let's keep boxing on our list and try to clean this up in the future.

@b-studios b-studios merged commit 75a7945 into master May 24, 2024
@marzipankaiser marzipankaiser deleted the fix/boxing-nothing branch July 30, 2025 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants