|
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 |
java.lang.Objectjavafe.tc.TypeCheck
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.)
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.
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:
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.
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 |
public static TypeCheck inst
Constructor Detail |
public TypeCheck()
inst
field to this instance. Only one instance should be created.
Also initializes PrepTypeDeclaration
.
Method Detail |
public FlowInsensitiveChecks makeFlowInsensitiveChecks()
FlowInsensitiveChecks
.
public void checkTypeSig(TypeSig s)
s
into the checked state. If any of the
supertypes of s
are not prepped, they are prepped
first.
public void checkTypeDecl(TypeDecl td)
td
into the checked state. If any of the
supertypes of s
are not prepped, they are prepped
first.
public Type getType(VarInit e)
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.
public Stmt getBranchLabel(BranchStmt s)
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.
public TypeSig getSig(TypeDecl d)
TypeSig
associated with a particular
TypeDecl
.
public TypeSig getSig(TypeName n)
TypeSig
associated with a particular
TypeName
.
Precondition: n has been resolved.
public TypeSig getRawSig(TypeName n)
public static java.lang.String getSignature(RoutineDecl r)
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.
public java.lang.String getName(RoutineDecl r)
RoutineDecl
.
Either of the form "method
All argument types are fully qualified if
Precondition: PrettyPrint.inst, and r non-null.
r
has been name resolved. The method/constructor
name is not qualified.
public java.lang.String getRoutineName(RoutineDecl r)
RoutineDecl
. Precondition: r non-null.
public boolean canAccess(TypeSig from, TypeSig target, int modifiers, ModifierPragmaVec pmodifiers)
Note: pmodifiers may be null.
public MethodDecl getOverrides(MethodDecl md)
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.
public Set getImplementsSet(ClassDecl cd, MethodDecl md)
MethodDecl
s that a given
class MethodDecl
implements. This information is
generated by the 'Prep' pass.
public Set getAllImplementsSet(MethodDecl md)
MethodDecl
s that a given
class MethodDecl
implements. This information is
generated by the 'Prep' pass.
public Set getImplementsSet(MethodDecl md)
MethodDecl
s that a
given interface MethodDecl
implements. This
information is generated by the 'Prep' pass.
public Set getAllOverrides(MethodDecl md)
MethodDecl
s that a given
MethodDecl
overrides or hides. This information is
generated by the 'Prep' pass.
|
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 |