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

Implement method parsing and type checking (closes #9) #22

Merged
merged 27 commits into from
Dec 1, 2021
Merged

Conversation

fo5for
Copy link
Collaborator

@fo5for fo5for commented Nov 24, 2021

Implemented:

  • Method declaration and definition processing, including typing and subsumption checking
  • Explicit and implicit method calls
  • Shadowing for implicit method calls in definitions
  • this identifier with shadowing semantics in method definitions

Issues:

  • ConstraintSolver.extrude does not handle the polarity of type variables in TypeRefs
  • Type simplification ignores type parameters of classes
  • DiffTests outputs the defined method type for methods declaration if the same method is both declared and defined in the class
  • To prohibit construction of abstract classes

fo5for and others added 14 commits November 24, 2021 19:20
Methods of polymorphic classes are now typed correctly.

Record field names now use `Var`s instead of plain strings to track
locations. Field order in outputs are shuffled and seem unstable.
Potentially due to the use of `Map` instead of `SortedMap` in
ConstraintSolver.
Also included field names in the `children` of `Sel`s, which was made
possible by changing field names to `Var`s in the last commit.
Broken due to polarity of `TypeRef`s in `ConstraintSolver.extrude`.

Deduplicated `Typer.MethodDef` with `MethodDef`.
Fixed more polymorphism issues, which requires implementing bounds on
rigidified variables.
@fo5for fo5for linked an issue Nov 24, 2021 that may be closed by this pull request
Copy link
Contributor

@LPTK LPTK left a comment

Choose a reason for hiding this comment

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

This is amazing, thanks!

However, I've outlined several places where the code seems unclear or needs some documentation/refactoring. Let's make sure to fix these before the merge.

shared/src/main/scala/mlscript/Typer.scala Outdated Show resolved Hide resolved
shared/src/test/diff/mlscript/Methods.mls Outdated Show resolved Hide resolved
shared/src/main/scala/mlscript/Typer.scala Outdated Show resolved Hide resolved
shared/src/main/scala/mlscript/Typer.scala Outdated Show resolved Hide resolved
shared/src/main/scala/mlscript/Typer.scala Outdated Show resolved Hide resolved
shared/src/main/scala/mlscript/Typer.scala Outdated Show resolved Hide resolved
shared/src/main/scala/mlscript/Typer.scala Outdated Show resolved Hide resolved
val decls = newMthDecls(tn.name)
val defs = newMthDefs(tn.name)
val rigidSubsMap = ctx.getTargsMaps(td.nme.name, "").getOrElse(Map.empty).collect {
case s -> (tv: TypeVariable) => tv -> freshenAbove(ctx.lvl, tv, true)
Copy link
Contributor

Choose a reason for hiding this comment

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

How can it be okay to filter out only the cases where the mapped value is a TypeVariable? That's very fishy. Couldn't it be a ProxyType at some point (maybe not now, but if the code base changes in the future)? Or an application Id[X] of the type Id[T] = T type? If we're indeed only interested in type variables here, this should be expressed in the type, to make sure we're not messing up, and for documentation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

targsMaps store the mapping from type parameters to the dummy TypeVariables, and to the rigidified TraitTaga when typing methods. It was originally just a map to TypeVariables before I realized the class type parameters should be rigidified when typing methods.

I couldn't come up with a way to express this invariant in the type. I tried to use TypeVariable \/ TraitTag, but it would require a use of asInstanceOf, as freshenAbove returns a SimpleType even when called directly with a TypeVariable. For now I have added 3 die statements before I can come up with a better solution.

I think your worry about the other cases came from nested TypeRefs or ProxyTypes in the body. They are in fact not handled by this map, but by the subsMap a few lines below. The TypeVariables we are collecting are the dummy type arguments created when typing the body of the TypeDef. The actually applied type arguments are on the rhs of subsMap. I believe it is handling nested AppliedTypes properly, as they would be typed as TypeRefs by targsAppOf (formerly targsMapOf. I am running out of names...).

However, as I was writing tests to test this out, I discovered that nested type arguments are not typed correctly, even in the mlscript branch:

class Foo[A]: { value: A }
class Bar[A]: Foo[Foo[A]]
//│ Defined class Foo

The TypeDef of Bar is not registered to the context, even though no error are emitted. I believe this is due to checkRegular returning false.

Copy link
Contributor

Choose a reason for hiding this comment

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

Okay, thanks for the explanation. Now I understand what you are doing, although I don't really agree with how it's done. See my other comment #22 (comment) for an idea to make the whole thing more functional, relying on computing the relevant information once, at the right place. We'd simply pass that relevant info along with each type definition being processed (instead of storing it in the context through the weird targsMaps mutable map), so that we can later perform subsumption checking after typing methods. Does that make sense to you?

@LPTK LPTK changed the title Implement methods (closes #9) Implement method parsing and type checking (closes #9) Nov 27, 2021
fo5for and others added 5 commits November 27, 2021 19:47
Cache results of `allBaseClasses` in the `Ctx`.
Renamed type provenance for type definitions.
Added comments for documentation and `die` statesments to express invariants...
Changed the use of empty strings in `Ctx.targsMaps` to options for clarity.
@LPTK
Copy link
Contributor

LPTK commented Nov 28, 2021

I think we can merge this, after you've addressed #22 (comment) and #22 (comment). Not sure why the CI is failing, though.

@LPTK
Copy link
Contributor

LPTK commented Nov 28, 2021

The CI was failing because of my parallel bug fix in 199e937

@LPTK
Copy link
Contributor

LPTK commented Nov 28, 2021

Oh and also the selection-typing part should be improved as we discussed: https://github.com/hkust-taco/mlscript/pull/22/files#diff-09ce6a8849c3c07173c504d6966f025cfa3338fa80afedecb4e77c6c013d50d3R660
Notably, code like err(msg"Class ${name} has no method ${fieldName.name}", term.toLoc) should be deduplicated.

@LPTK LPTK mentioned this pull request Nov 30, 2021
4 tasks
@fo5for
Copy link
Collaborator Author

fo5for commented Nov 30, 2021

Oh and also the selection-typing part should be improved as we discussed: https://github.com/hkust-taco/mlscript/pull/22/files#diff-09ce6a8849c3c07173c504d6966f025cfa3338fa80afedecb4e77c6c013d50d3R660 Notably, code like err(msg"Class ${name} has no method ${fieldName.name}", term.toLoc) should be deduplicated.

Addressed in bc397a9

@LPTK
Copy link
Contributor

LPTK commented Dec 1, 2021

Okay thanks, that's really good work! The processTypeDefs implementation is a lot clearer now. I just pushed a few improvements, and we're ready to merge.

@LPTK LPTK merged commit da8ec6b into mlscript Dec 1, 2021
@LPTK LPTK deleted the methods branch December 1, 2021 02:12
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.

Implement method parsing and type checking
2 participants