Overview | Package | Class | Use | Tree | Deprecated | Index | Help
| ESC/Java2 © 2003,2004,2005 David Cok and Joseph Kiniry © 2005 UCD Dublin © 2003,2004 Radboud University Nijmegen © 1999,2000 Compaq Computer Corporation © 1997,1998,1999 Digital Equipment Corporation All Rights Reserved
PREV CLASS NEXT CLASS | FRAMES NO FRAMES
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD

## javafe.tc
Class TypeCheck

    java.lang.Object
      javafe.tc.TypeCheck

Direct Known Subclasses:
  TypeCheck

public class TypeCheck
extends java.lang.Object

The `TypeCheck` class contains methods to disambiguate, resolve, and check type declarations. (Before methods in this class can be called, the `TypeSig` class must be initialized.)

### Overview of checking, resolution, and disambiguation

This description is out of date, particularly with respect to the names of classes.

Checking involves performing the static checks specified by the Java language specification.

Resolution involves connecting symbolic references in the parse tree to objects representing declarations of the referred-to entities. The parser generates a number of nodes -- instances of `Identifier`, `FieldAccess`, and `MethodDecl` -- containing identifiers found in the input plus a `decl` field which is initially `null`. Resolution sets these `decl` fields to point to the declaration referred to by the identifiers. Similarly, `TypeName` nodes have a `sig` field which is initially `null` and which must be resolved to an instance of `TypeSig`. For example, the name `java.lang.String` appearing in a type context would be parsed to a `TypeName`; resolution of this node would point its `sig` field to the `TypeSig` object representing Java's standard `String` type.

Disambiguation deals with "ambiguous names" in Java (see Section Six of the Java language specification, or this document). These are qualified names of the form `I1.I2...In` that appear in an expression context. For such a name, `I1` could be a local variable or a field of `this`, or some prefix of the name could be the fully-qualified name of a type, as in `java.lang.String.concat`.

When it encounters an ambiguous name, the parser generates either an `AmbiguousVariableAccess` or `AmbiguousMethodInvocation` node depending on the context. These are leaf nodes. In these cases, disambiguation involves replacing these nodes with appropriate `VariableAccess` or `MethodInvocation` nodes; these are non-leaf nodes, and in general the replacement might be fairly deep.

As an example of disambiguation, assume the name `x.y` is parsed as an `AmbiguousVariableAccess`. Assume further that no local named `x` is in scope, the current scope is in an instance method for a class that has a field named `x`. In this case, disambiguation would replace this `AmbiguousVariableAccess` with:

> `(FieldAccess (FieldAccess this x) y)`

that is, an instance of `FieldAccess` whose `id` field was `y` and whose `expr` field was another `FieldAccess` whose `id` field was `x` and whose `expr` field was an instance of `ThisExpr`.

An alternative design for disambiguation and resolution was considered. In this design, the `Name` class, the three subclasses of `FieldAccess`, and the three subclasses of `MethodInvocation` would be replaced with a new expression class that looked something like:

>      class DotExpr extends Expr {
>      int tag; // Indicates the kind of dot
>      Expr expr;
>      Identifier id;
>      }

When confronted with phrases of the form `I1.I2...In`, the parser would generate trees of DotExpr nodes all with the same tag, this tag indicating that the meaning of the dot was ambiguous. Disambiguation would involve replacing this ambiguous tag with a tag whose meaning was clear (e.g., a tag that meant "select a type from a package"). Resolution would involve using our generic decoration mechanism to link certain of these nodes with the declarations to which they refer.

The advantages of this approach over the one we selected is that it is more conventional (it's been used, for example, in compilers for the Modula family of languages), it has a simpler class hierarchy, and it does not involve mutating the structure of the parse tree. The primary advantage of our approach is that we capture many more invariants in the type system, leaving less to go wrong at run-time. It is mostly for this reason that we selected it. In addition, our approach takes less space to represent type names, avoids downcasting (which can be costly time-wise), and is more friendly to the "visitor" pattern.

### Staging the processing of type declarations

Resolving and checking a type declaration usually involves looking at other declarations to which it refers. Finding, reading, and processing referred-to types makes resolution and checking fairly complicated. As a result, we have decomposed it up into smaller steps. Type declarations move through a number of states as the resolution and checking process procedes. In addition to making the overall processing of type declarations conceptually more manageable, this decomposition has two other benefits:

- Handling cycles. As mentioned above, processing one type may involve processing types to which it refers. However, two types may refer to each other, making it impossible to process any one of them "first." Decomposing the processing into stages helps us handle such cycles.
- Improving performance. Processing one type declaration does not always involve fully processing the declarations to which it refers. How much processing is required of a referred-to type depends on the manner in which it is referred (e.g., in a method signature versus as a superclass). Decomposing processing into stages allows us to be lazy in processing referred-to types, that is, allowing us to process them only to the extent that is necessary and no further.

To support the lazy handling of type declarations, type declarations are represented using two objects: `TypeDecl`s and `TypeSig`s. `TypeDecl` objects represents the actual parse tree of a declaration. `TypeSig` objects refer to `TypeDecl` objects. Rather than point directly to `TypeDecl`, most references to type declarations point to `TypeSig` objects instead. This extra level of indirection allows us to defer parsing of type declarations until the parse tree is really needed.

Details of the states of type declarations are found with documentation of the `TypeSig` class.

See Also:
  `TypeSig`, `Env`, `TypeDecl`, `TypeName`, `FieldAccess`

Field Summary
`static TypeCheck` | `inst` A (possibly extended) instance of TypeCheck.

Constructor Summary
`TypeCheck()` Creates a instance of TypeCheck, and sets the `inst` field to this instance.

Method Summary
`boolean` | `canAccess(TypeSig from, TypeSig target, int modifiers, ModifierPragmaVec pmodifiers)` Can a member of type target with modifiers modifiers/pmodifiers be accessed by code located in from?
`void` | `checkTypeDecl(TypeDecl td)` Moves `td` into the checked state.
`void` | `checkTypeSig(TypeSig s)` Moves `s` into the checked state.
`Set` | `getAllImplementsSet(MethodDecl md)` Retrieves the set of interface `MethodDecl`s that a given class `MethodDecl` implements.
`Set` | `getAllOverrides(MethodDecl md)` Retrieves the set of `MethodDecl`s that a given `MethodDecl` overrides or hides.
`Stmt` | `getBranchLabel(BranchStmt s)` Retrieves the `Stmt` target of a `BranchStmt`.
`Set` | `getImplementsSet(ClassDecl cd, MethodDecl md)` Retrieves the set of interface `MethodDecl`s that a given class `MethodDecl` implements.
`Set` | `getImplementsSet(MethodDecl md)` Retrieves the set of interface `MethodDecl`s that a given interface `MethodDecl` implements.
`java.lang.String` | `getName(RoutineDecl r)` Returns the user-readable name for a `RoutineDecl`.
`MethodDecl` | `getOverrides(MethodDecl md)` Retrieves the class `MethodDecl` that a given class `MethodDecl` overrides.
`TypeSig` | `getRawSig(TypeName n)`
`java.lang.String` | `getRoutineName(RoutineDecl r)` Returns the user-readable simple name for a `RoutineDecl`.
`TypeSig` | `getSig(TypeDecl d)` Retrieves the `TypeSig` associated with a particular `TypeDecl`.
`TypeSig` | `getSig(TypeName n)` Retrieves the `TypeSig` associated with a particular `TypeName`.
`static java.lang.String` | `getSignature(RoutineDecl r)` Construct a `String` listing the signature of a `RoutineDecl`, omitting the return type and throws causes if any.
`Type` | `getType(VarInit e)` Retrieves the `Type` of a `VarInit`.
`FlowInsensitiveChecks` | `makeFlowInsensitiveChecks()` Called to obtain the algorithm for performing name resolution and type checking.

Methods inherited from class java.lang.Object
`clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

Field Detail

### inst

    public static TypeCheck inst

  A (possibly extended) instance of TypeCheck.

Constructor Detail

### TypeCheck

    public TypeCheck()

  Creates a instance of TypeCheck, and sets the `inst` field to this instance. Only one instance should be created. Also initializes `PrepTypeDeclaration`.

Method Detail

### makeFlowInsensitiveChecks

    public FlowInsensitiveChecks makeFlowInsensitiveChecks()

  Called to obtain the algorithm for performing name resolution and type checking. By default, returns an instance of `FlowInsensitiveChecks`.

### checkTypeSig

    public void checkTypeSig(TypeSig s)

  Moves `s` into the checked state. If any of the supertypes of `s` are not prepped, they are prepped first.

### checkTypeDecl

    public void checkTypeDecl(TypeDecl td)

  Moves `td` into the checked state. If any of the supertypes of `s` are not prepped, they are prepped first.

### getType

    public Type getType(VarInit e)

  Retrieves the `Type` of a `VarInit`. This type is associated with an expression by the typechecking pass. If the expression does not have an associated type, then `Assert.fail` is called.

### getBranchLabel

    public Stmt getBranchLabel(BranchStmt s)

  Retrieves the `Stmt` target of a `BranchStmt`. This `Stmt` may be mentioned either explicitly (as in `break label;`), or implicitly (as in `break;`) by the `BranchStmt`. The correct `Stmt` target is associated with the `BranchStmt` by the typechecking pass. This type is associated with an expression by the typechecking pass. If the `BranchStmt` does not have an associated `Stmt` target, then `Assert.fail` is called.

### getSig

    public TypeSig getSig(TypeDecl d)

  Retrieves the `TypeSig` associated with a particular `TypeDecl`.

### getSig

    public TypeSig getSig(TypeName n)

  Retrieves the `TypeSig` associated with a particular `TypeName`. Precondition: n has been resolved.

### getRawSig

    public TypeSig getRawSig(TypeName n)

### getSignature

    public static java.lang.String getSignature(RoutineDecl r)

  Construct a `String` listing the signature of a `RoutineDecl`, omitting the return type and throws causes if any.

  All types are fully qualified if `r` has been name resolved.

  Sample output: "(int, javafe.tc.TypeSig, char[])"

  Precondition: PrettyPrint.inst, and r non-null.

### getName

    public java.lang.String getName(RoutineDecl r)

  Returns the user-readable name for a `RoutineDecl`.

  Either of the form "method ()" or the form "constructor ()".

  All argument types are fully qualified if `r` has been name resolved. The method/constructor name is not qualified.

  Precondition: PrettyPrint.inst, and r non-null.

### getRoutineName

    public java.lang.String getRoutineName(RoutineDecl r)

  Returns the user-readable simple name for a `RoutineDecl`.

  Precondition: r non-null.

### canAccess

    public boolean canAccess(TypeSig from,
                             TypeSig target,
                             int modifiers,
                             ModifierPragmaVec pmodifiers)

  Can a member of type target with modifiers modifiers/pmodifiers be accessed by code located in from?

  Note: pmodifiers may be null.

### getOverrides

    public MethodDecl getOverrides(MethodDecl md)

  Retrieves the class `MethodDecl` that a given class `MethodDecl` overrides. If there is no overridden `MethodDecl` in a superclass, then return `null`. The returned `MethodDecl` may be abstract. If multiple class `MethodDecl`'s are overridden, it returns the one lowest in the class hierarchy (furthest away from java.lang.Object). This information is generated by the 'Prep' pass.

### getImplementsSet

    public Set getImplementsSet(ClassDecl cd,
                                MethodDecl md)

  Retrieves the set of interface `MethodDecl`s that a given class `MethodDecl` implements. This information is generated by the 'Prep' pass.

### getAllImplementsSet

    public Set getAllImplementsSet(MethodDecl md)

  Retrieves the set of interface `MethodDecl`s that a given class `MethodDecl` implements. This information is generated by the 'Prep' pass.

### getImplementsSet

    public Set getImplementsSet(MethodDecl md)

  Retrieves the set of interface `MethodDecl`s that a given interface `MethodDecl` implements. This information is generated by the 'Prep' pass.

### getAllOverrides

    public Set getAllOverrides(MethodDecl md)

  Retrieves the set of `MethodDecl`s that a given `MethodDecl` overrides or hides. This information is generated by the 'Prep' pass.

Overview | Package | Class | Use | Tree | Deprecated | Index | Help
| ESC/Java2 © 2003,2004,2005 David Cok and Joseph Kiniry © 2005 UCD Dublin © 2003,2004 Radboud University Nijmegen © 1999,2000 Compaq Computer Corporation © 1997,1998,1999 Digital Equipment Corporation All Rights Reserved
PREV CLASS NEXT CLASS | FRAMES NO FRAMES
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD

The ESC/Java2 Project Homepage