Implicit definitions in explicit scope change the scope of regular definitions
Name binding for class declarations with inheritance in Java is specified as follows:
ClassDec(ClassDecHead(m*, c, tp*, SuperDec(sc), _), body): defines Type c of type RefType(TypeName(c), None()) of kind Class() of modifiers m* of type-parameters tp* imports Field, imported Field, Method, imported Method from Type sc implicitly defines Field "this" of type RefType(TypeName(c), None()) in body implicitly defines Field "super" of type st in body where sc has type st scopes Type, TypeParam, Field, Method, Constructor
The implicit definitions are only defined in
body
to prevent access tothis
andsuper
from outside this class.
However, this generates an anonymous scope for all definitions inside the body of a class, putting field and method declarations also in some anonymous scope. Because they are in an anonymous scope, fields and methods can never be accessed outside of this class, which is undesired.
For the example program:
package p; class A { int a; } class B extends A { int b = a; // Resolution of a fails }
the following definitions are stored in the index:
def / Type:"A"#0 / Package:"p" / DefaultPackage:Default() / def / Type:"B"#0 / Package:"p" / DefaultPackage:Default() / def / Field:"a"#0 / anon 0 / Type:"A"#0 / Package:"p" / DefaultPackage:Default() / def / Field:"b"#0 / anon 0 / Type:"B"#0 / Package:"p" / DefaultPackage:Default() / def / Field:"super"#0 / anon 3 / def / Field:"this"#0 / anon 2 / def / Field:"this"#0 / anon 1 /
The problem is that both field definitions have an anonymous scope. If I remove the
in body
part of the implicit definitions, this anonymous scope is not there.
For reference, here is the AST of the program:
Submitted by Gabriël Konat on 19 March 2014 at 10:29File( CompilationUnit( "current"{ Def( URI( Language("Java") , [ID(NablNsCompilationUnit(), "current", Unique("/Users/gohla/Spoofax/Workspaces/NBL/java-single-ex/test.jav/0")), Anonymous("/Users/gohla/Spoofax/Workspaces/NBL/java-single-ex/test.jav/0")] ) ) } , [] , DefaultPackageDec( Default(){Def( URI(Language("Java"), [ID(NablNsDefaultPackage(), Default(), NonUnique())]) )} , PackageDec( [] , "p"{ Def( URI( Language("Java") , [ID(NablNsPackage(), "p", NonUnique()), ID(NablNsDefaultPackage(), Default(), NonUnique())] ) ) } , [ ClassDec( ClassDecHead([Default()], "A"{ Def( URI( Language("Java") , [ ID(NablNsType(), "A", Unique("/Users/gohla/Spoofax/Workspaces/NBL/java-single-ex/test.jav/0")) , ID(NablNsPackage(), "p", NonUnique()) , ID(NablNsDefaultPackage(), Default(), NonUnique()) ] ) ) }, None(), None(), None()) , ClassBody([FieldDec([Default()], Int(){(Type(), Result(9))}, VarDec("a"{ Def( URI( Language("Java") , [ ID(NablNsField(), "a", Unique("/Users/gohla/Spoofax/Workspaces/NBL/java-single-ex/test.jav/0")) , Anonymous("/Users/gohla/Spoofax/Workspaces/NBL/java-single-ex/test.jav/0") , ID(NablNsType(), "A", Unique("/Users/gohla/Spoofax/Workspaces/NBL/java-single-ex/test.jav/0")) , ID(NablNsPackage(), "p", NonUnique()) , ID(NablNsDefaultPackage(), Default(), NonUnique()) ] ) ) }))]){ Scope( [ ( NablNsField() , URI( Language("Java") , [ Anonymous("/Users/gohla/Spoofax/Workspaces/NBL/java-single-ex/test.jav/0") , ID(NablNsType(), "A", Unique("/Users/gohla/Spoofax/Workspaces/NBL/java-single-ex/test.jav/0")) , ID(NablNsPackage(), "p", NonUnique()){Barrier([NablNsPackage(), NablNsType()])} , ID(NablNsDefaultPackage(), Default(), NonUnique()){Barrier([NablNsPackage(), NablNsType()])} ] ) ) ] ) } ) , ClassDec( ClassDecHead( [Default()] , "B"{ Def( URI( Language("Java") , [ ID(NablNsType(), "B", Unique("/Users/gohla/Spoofax/Workspaces/NBL/java-single-ex/test.jav/0")) , ID(NablNsPackage(), "p", NonUnique()) , ID(NablNsDefaultPackage(), Default(), NonUnique()) ] ) ) } , None() , SuperDec(ClassType(TypeName("A"{Use(Result(116))}){Use(Result(120)), (Type(), Result(46))}, None()){(Type(), Result(119))}) , None() ) , ClassBody( [FieldDec([Default()], Int(){(Type(), Result(9))}, VarDec("b"{ Def( URI( Language("Java") , [ ID(NablNsField(), "b", Unique("/Users/gohla/Spoofax/Workspaces/NBL/java-single-ex/test.jav/0")) , Anonymous("/Users/gohla/Spoofax/Workspaces/NBL/java-single-ex/test.jav/0") , ID(NablNsType(), "B", Unique("/Users/gohla/Spoofax/Workspaces/NBL/java-single-ex/test.jav/0")) , ID(NablNsPackage(), "p", NonUnique()) , ID(NablNsDefaultPackage(), Default(), NonUnique()) ] ) ) }, ExprName("a"{Use(Result(75))}){(Type(), Result(79))}))] ){ Scope( [ ( NablNsField() , URI( Language("Java") , [ Anonymous("/Users/gohla/Spoofax/Workspaces/NBL/java-single-ex/test.jav/0") , ID(NablNsType(), "B", Unique("/Users/gohla/Spoofax/Workspaces/NBL/java-single-ex/test.jav/0")) , ID(NablNsPackage(), "p", NonUnique()){Barrier([NablNsPackage(), NablNsType()])} , ID(NablNsDefaultPackage(), Default(), NonUnique()){Barrier([NablNsPackage(), NablNsType()])} ] ) ) ] ) } ) ] ) ) ) ){ Scope( [(NablNsCompilationUnit(), URI(Language("Java"), [Anonymous("/Users/gohla/Spoofax/Workspaces/NBL/java-single-ex/test.jav/0")]))] ) }
Issue Log
Is this really a scope for all namespaces? If it is only for fields, this would make sense and could be avoided by putting
this
into a separate namespace. The annotation on the class body states only a scope for fields.
You’re right, it’s only for fields, not for methods. I’ll work around it for now by putting
this
in a separate namespace. I still think this behavior would confuse users, is it possible to only generate an anonymous scope for the implicit definitions?
I don’t think that this will fix it, since the behaviour is exactly the same for explicit definitions in scope. Each
defines ... in t
clause creates a scope att
. Why should this be different for implicit definitions?You could also drop the
in body
part, and the definitions will still be scoped by the class declaration. However, this will import the implicit definitions into subclasses.
Log in to post comments