@@ -110,18 +110,15 @@ pragma[nomagic]
110110private ItemNode getAChildSuccessor ( ItemNode item , string name , SuccessorKind kind ) {
111111 item = result .getImmediateParent ( ) and
112112 name = result .getName ( ) and
113+ // Associated items in `impl` and `trait` blocks are handled elsewhere
114+ not ( item instanceof ImplOrTraitItemNode and result instanceof AssocItem ) and
113115 // type parameters are only available inside the declaring item
114116 if result instanceof TypeParam
115117 then kind .isInternal ( )
116118 else
117- // associated items must always be qualified, also within the declaring
118- // item (using `Self`)
119- if item instanceof ImplOrTraitItemNode and result instanceof AssocItem
120- then kind .isExternal ( )
121- else
122- if result .isPublic ( )
123- then kind .isBoth ( )
124- else kind .isInternal ( )
119+ if result .isPublic ( )
120+ then kind .isBoth ( )
121+ else kind .isInternal ( )
125122}
126123
127124private module UseOption = Option< Use > ;
@@ -327,30 +324,25 @@ abstract class ItemNode extends Locatable {
327324 )
328325 )
329326 or
330- // a trait has access to the associated items of its supertraits
331327 this =
332328 any ( TraitItemNodeImpl trait |
333- result = trait .resolveABoundCand ( ) .getASuccessor ( name , kind , useOpt ) and
334- kind .isExternalOrBoth ( ) and
335- result instanceof AssocItemNode and
336- not trait .hasAssocItem ( name )
337- )
329+ result = trait .getAssocItem ( name )
330+ or
331+ // a trait has access to the associated items of its supertraits
332+ not trait .hasAssocItem ( name ) and
333+ result = trait .resolveABoundCand ( ) .getASuccessor ( name ) .( AssocItemNode )
334+ ) and
335+ kind .isExternal ( ) and
336+ useOpt .isNone ( )
338337 or
339338 // items made available by an implementation where `this` is the implementing type
340- typeImplEdge ( this , _, name , kind , result , useOpt )
341- or
342- // trait items with default implementations made available in an implementation
343- exists ( ImplItemNodeImpl impl , TraitItemNode trait |
344- this = impl and
345- trait = impl .resolveTraitTyCand ( ) and
346- result = trait .getASuccessor ( name , kind , useOpt ) and
347- // do not inherit default implementations from super traits; those are inherited by
348- // their `impl` blocks
349- result = trait .getAssocItem ( name ) and
350- result .( AssocItemNode ) .hasImplementation ( ) and
351- kind .isExternalOrBoth ( ) and
352- not impl .hasAssocItem ( name )
353- )
339+ typeImplEdge ( this , _, name , result ) and
340+ kind .isExternal ( ) and
341+ useOpt .isNone ( )
342+ or
343+ implEdge ( this , name , result ) and
344+ kind .isExternal ( ) and
345+ useOpt .isNone ( )
354346 or
355347 // type parameters have access to the associated items of its bounds
356348 result =
@@ -413,14 +405,8 @@ abstract class ItemNode extends Locatable {
413405 this instanceof SourceFile and
414406 builtin ( name , result )
415407 or
416- exists ( ImplOrTraitItemNode i |
417- name = "Self" and
418- this = i .getAnItemInSelfScope ( )
419- |
420- result = i .( Trait )
421- or
422- result = i .( ImplItemNodeImpl ) .resolveSelfTyCand ( )
423- )
408+ name = "Self" and
409+ this = result .( ImplOrTraitItemNode ) .getAnItemInSelfScope ( )
424410 or
425411 name = "crate" and
426412 this = result .( CrateItemNode ) .getASourceFile ( )
@@ -755,7 +741,7 @@ abstract class ImplOrTraitItemNode extends ItemNode {
755741 }
756742
757743 /** Gets an associated item belonging to this trait or `impl` block. */
758- abstract AssocItemNode getAnAssocItem ( ) ;
744+ AssocItemNode getAnAssocItem ( ) { result = this . getADescendant ( ) }
759745
760746 /** Gets the associated item named `name` belonging to this trait or `impl` block. */
761747 pragma [ nomagic]
@@ -807,12 +793,12 @@ final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
807793
808794 TraitItemNode resolveTraitTy ( ) { result = resolvePath ( this .getTraitPath ( ) ) }
809795
810- override AssocItemNode getAnAssocItem ( ) { result = this .getADescendant ( ) }
811-
812796 override string getName ( ) { result = "(impl)" }
813797
814798 override Namespace getNamespace ( ) {
815- result .isType ( ) // can be referenced with `Self`
799+ // `impl` blocks are referred to using `Self` paths which can appear both as
800+ // types and as values (when the implementing type is a tuple-like struct).
801+ result .isType ( ) or result .isValue ( )
816802 }
817803
818804 override TypeParam getTypeParam ( int i ) { result = super .getGenericParamList ( ) .getTypeParam ( i ) }
@@ -985,6 +971,18 @@ private class ImplItemNodeImpl extends ImplItemNode {
985971 }
986972
987973 TraitItemNodeImpl resolveTraitTyCand ( ) { result = resolvePathCand ( this .getTraitPath ( ) ) }
974+
975+ /**
976+ * Gets the associated item named `name` in this impl block or the default
977+ * inherited from the trait being implemented.
978+ */
979+ AssocItemNode getAssocItemOrDefault ( string name ) {
980+ result = this .getAssocItem ( name )
981+ or
982+ not this .hasAssocItem ( name ) and
983+ result = this .resolveTraitTyCand ( ) .getAssocItem ( name ) and
984+ result .hasImplementation ( )
985+ }
988986}
989987
990988private class StructItemNode extends TypeItemTypeItemNode , ParameterizableItemNode instanceof Struct
@@ -1020,8 +1018,6 @@ final class TraitItemNode extends ImplOrTraitItemNode, TypeItemNode instanceof T
10201018
10211019 ItemNode resolveABound ( ) { result = this .resolveBound ( _) }
10221020
1023- override AssocItemNode getAnAssocItem ( ) { result = this .getADescendant ( ) }
1024-
10251021 override string getName ( ) { result = Trait .super .getName ( ) .getText ( ) }
10261022
10271023 override Namespace getNamespace ( ) { result .isType ( ) }
@@ -1790,7 +1786,17 @@ private module DollarCrateResolution {
17901786
17911787pragma [ nomagic]
17921788private ItemNode resolvePathCand0 ( PathExt path , Namespace ns ) {
1793- result = unqualifiedPathLookup ( path , ns , _)
1789+ exists ( ItemNode res |
1790+ res = unqualifiedPathLookup ( path , ns , _) and
1791+ if
1792+ // `Self` paths that are not used as qualifiers (for instance `Self` in
1793+ // `fn(..) -> Self`) should resolve to the type being implemented.
1794+ not any ( PathExt parent ) .getQualifier ( ) = path and
1795+ isUnqualifiedSelfPath ( path ) and
1796+ res instanceof ImplItemNode
1797+ then result = res .( ImplItemNodeImpl ) .resolveSelfTyCand ( )
1798+ else result = res
1799+ )
17941800 or
17951801 DollarCrateResolution:: resolveDollarCrate ( path , result ) and
17961802 ns = result .getNamespace ( )
@@ -1852,35 +1858,12 @@ private predicate checkQualifiedVisibility(
18521858 not i instanceof TypeParam
18531859}
18541860
1855- pragma [ nomagic]
1856- private predicate isImplSelfQualifiedPath (
1857- ImplItemNode impl , PathExt qualifier , PathExt path , string name
1858- ) {
1859- qualifier = impl .getASelfPath ( ) and
1860- qualifier = path .getQualifier ( ) and
1861- name = path .getText ( )
1862- }
1863-
1864- private ItemNode resolveImplSelfQualified ( PathExt qualifier , PathExt path , Namespace ns ) {
1865- exists ( ImplItemNode impl , string name |
1866- isImplSelfQualifiedPath ( impl , qualifier , path , name ) and
1867- result = impl .getAssocItem ( name ) and
1868- ns = result .getNamespace ( )
1869- )
1870- }
1871-
18721861/**
18731862 * Gets the item that `path` resolves to in `ns` when `qualifier` is the
18741863 * qualifier of `path` and `qualifier` resolves to `q`, if any.
18751864 */
18761865pragma [ nomagic]
18771866private ItemNode resolvePathCandQualified ( PathExt qualifier , ItemNode q , PathExt path , Namespace ns ) {
1878- // Special case for `Self::Assoc`; this always refers to the associated
1879- // item in the enclosing `impl` block, if available.
1880- q = resolvePathCandQualifier ( qualifier , path , _) and
1881- result = resolveImplSelfQualified ( qualifier , path , ns )
1882- or
1883- not exists ( resolveImplSelfQualified ( qualifier , path , ns ) ) and
18841867 exists ( string name , SuccessorKind kind , UseOption useOpt |
18851868 q = resolvePathCandQualifier ( qualifier , path , name ) and
18861869 result = getASuccessor ( q , name , ns , kind , useOpt ) and
@@ -1940,6 +1923,37 @@ private predicate macroExportEdge(CrateItemNode crate, string name, MacroItemNod
19401923 name = macro .getName ( )
19411924}
19421925
1926+ /**
1927+ * Holds if a `Self` path inside `impl` might refer to a function named `name`
1928+ * from another impl block.
1929+ */
1930+ pragma [ nomagic]
1931+ private predicate relevantSelfFunctionName ( ImplItemNodeImpl impl , string name ) {
1932+ any ( Path path | path .getQualifier ( ) = impl .getASelfPath ( ) ) .getText ( ) = name and
1933+ not impl .hasAssocItem ( name )
1934+ }
1935+
1936+ /**
1937+ * Holds if `impl` has a `node` available externally at `name`.
1938+ *
1939+ * Since `Self` in an impl block resolves to the impl block, this corresponds to
1940+ * the items that should be available on `Self` within the `impl` block.
1941+ */
1942+ private predicate implEdge ( ImplItemNodeImpl impl , string name , ItemNode node ) {
1943+ node = impl .getAssocItemOrDefault ( name )
1944+ or
1945+ // Associated types from the implemented trait are available on `Self`.
1946+ not impl .hasAssocItem ( name ) and
1947+ node = impl .resolveTraitTyCand ( ) .getASuccessor ( name ) .( TypeAliasItemNode )
1948+ or
1949+ // Items available on the implementing type are available on `Self`. We only
1950+ // add these edges when they are relevant. If a type has `n` impl blocks with
1951+ // `m` functions each, we would otherwise end up always constructing something
1952+ // proportional to `O(n * m)`.
1953+ relevantSelfFunctionName ( impl , name ) and
1954+ node = impl .resolveSelfTyCand ( ) .getASuccessor ( name )
1955+ }
1956+
19431957/**
19441958 * Holds if item `i` contains a `mod` or `extern crate` definition that
19451959 * makes the macro `macro` named `name` available using a `#[macro_use]`
@@ -2009,9 +2023,10 @@ private ItemNode resolvePathCand(PathExt path) {
20092023
20102024/** Get a trait that should be visible when `path` resolves to `node`, if any. */
20112025private Trait getResolvePathTraitUsed ( PathExt path , AssocItemNode node ) {
2012- exists ( TypeItemNode type , ImplItemNodeImpl impl |
2013- node = resolvePathCandQualified ( _, type , path , _) and
2014- typeImplEdge ( type , impl , _, _, node , _) and
2026+ exists ( TypeItemNode type , ItemNode qual , ImplItemNodeImpl impl |
2027+ node = resolvePathCandQualified ( _, qual , path , _) and
2028+ type = [ qual , qual .( ImplItemNodeImpl ) .resolveSelfTyCand ( ) ] and
2029+ typeImplEdge ( type , impl , _, node ) and
20152030 result = impl .resolveTraitTyCand ( )
20162031 )
20172032}
@@ -2179,15 +2194,17 @@ private predicate externCrateEdge(
21792194
21802195/**
21812196 * Holds if `typeItem` is the implementing type of `impl` and the implementation
2182- * makes `assoc` available as `name` at `kind` .
2197+ * makes `assoc` available as `name`.
21832198 */
21842199private predicate typeImplEdge (
2185- TypeItemNode typeItem , ImplItemNodeImpl impl , string name , SuccessorKind kind ,
2186- AssocItemNode assoc , UseOption useOpt
2200+ TypeItemNode typeItem , ImplItemNodeImpl impl , string name , AssocItemNode assoc
21872201) {
2202+ assoc = impl .getAssocItemOrDefault ( name ) and
21882203 typeItem = impl .resolveSelfTyCand ( ) and
2189- assoc = impl .getASuccessor ( name , kind , useOpt ) and
2190- kind .isExternalOrBoth ( )
2204+ // Functions in `impl` blocks are made available on the implementing type
2205+ // (e.g., `S::fun` is valid) but associated types are not (e.g., `S::Output`
2206+ // is invalid).
2207+ not assoc instanceof TypeAlias
21912208}
21922209
21932210pragma [ nomagic]
0 commit comments