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

Ben's Proposal #3

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Ben's Proposal #3

wants to merge 3 commits into from

Conversation

montymxb
Copy link
Member

@montymxb montymxb commented Mar 5, 2024

No description provided.

Copy link
Collaborator

@JohannesMeierSE JohannesMeierSE left a comment

Choose a reason for hiding this comment

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

First of all, thanks for your proposal @montymxb ! It helped me to dive into type checking and to identify several challenges, I didn't thought about before.

At first, I missed your proposal, but finally, I saw, that you continued the proposal of Mark, my bad ...

In general, I had several problems to understand the ideas behind: Therefore I asked lots of questions, which might sound negative. But in my eyes, it is "normal" to have problems to understand the ideas of others, and it is the only chance for us to combine the best design for Typir from multiple, different proposals. I am looking forward to discuss the proposals in our next meetings!

My comments to Mark's part (which I wrote earlier):

  • I had some problems to understand several concepts of the proposal, not because of the proposal itself, but because of my lack of knowledge about type checking concepts. Therefore, some of my comments might be missleading.
  • Could you sketch an example, how to apply the type system? That would help me to understand the ideas behind.
  • (I didn't reviewed all kinds.)

import type { TypeSystem } from "./type-system";
import { Disposable } from "./utils";

export interface TypeCategory<T> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

What is a type category? Could you add some comments?

import { Disposable } from "./utils";

export interface Type<T> {
readonly literal?: T;
Copy link
Collaborator

Choose a reason for hiding this comment

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

What is T and the literal? Would AstNode be a value for T in the context of Langium? If a type like string is the type for multiple literals, do I have multiple Type instances representing string, one for each literal?


export interface Type<T> {
readonly literal?: T;
readonly members: Iterable<TypeMember<T>>;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does it really make sense to have members, even when lots of types don't have any members, e.g. all primitive types like int, string, ...? For functions, I would prefer to call them "parameters" instead of "members" ...

readonly typeParameters: TypeParameter<T>[];
readonly typeArguments: Type<T>[];
applyTypeArguments(args: Type<T>[]): FunctionType<T>;
readonly parameters: FunctionParameter<T>;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Sorry, I am lost: What are members in contrast to parameters?

(What about FunctionParameter<T> extends TypeMember<T>?)

assignable(callback: AssignabilityCallback<PrimitiveType<T>>): Disposable;
}

export interface PrimitiveTypeConstant<T> extends Type<T> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Did I understand correctly, that PrimitiveTypeConstant is an instance/element of the set defined by a PrimitiveType?

return reachableTypes.has(fromType);
}

inferType(expression: any): any {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does Typir provides this as default implementation? So the user of Typir adapts the inference by sub-classing Typir and overriding this function? In Langium, we would register a different implementation for an "inference service"

@@ -0,0 +1,228 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
Copy link
Collaborator

Choose a reason for hiding this comment

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

Now I found the correct file to review, sorry

// binding symbols with types in the environment
//
const xSymbol = typirInstance.loadSymbol('x', intType);
const ySymbol = typirInstance.loadSymbol('y', boolType);
Copy link
Collaborator

Choose a reason for hiding this comment

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

What are "x" and "y"? I don't see them again in the example AST ...


// Example concrete visitor implementing TypirVisitor
// Which accepts an AST object and updates the typir instance w/ types, relationships, etc.
class ExampleASTVisitor implements TypirVisitor {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I still have the feeling, that I didn't got the main idea behind the visitor.

From my current thinking, the visitor seems to be not necessary, since the visitor provides only API (a single line!):
Neither the traversal of the AST (which calls this API) nor the implementation of the API (what is called) seems to be generic, but both are depending on our current DSL. Therefore, what is the benefit of the API? Where is some simplification or reuse or ... ?

// inject the visitor into the typir instance, and get the visitor to traverse the AST
// result is that the typir instance is updated with the relationships and types defined in the visitor
// and then we can use the typir instance to do type inference, type checking, etc.
const visitor = new ExampleASTVisitor(typirInstance);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Regarding your explanations (well, what I belief to understand), the visitor aims to fill the type graph with information about existing types and their relationships by traversing the current AST:

Why can I call isAssignable (line 202) before using the visitor (line 225)?

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.

None yet

3 participants