Skip to content

Commit e60d1dd

Browse files
committed
ExtractDependencies: more robust cycle check
Checking for seen types alone wasn't robust enough since the cycle might involve a type`=:=` but not `eq` to a type we've already seen. Fixes #13575.
1 parent 164b5d8 commit e60d1dd

File tree

6 files changed

+71
-5
lines changed

6 files changed

+71
-5
lines changed

compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -447,18 +447,20 @@ private class ExtractDependenciesCollector extends tpd.TreeTraverser { thisTreeT
447447
private abstract class TypeDependencyTraverser(using Context) extends TypeTraverser() {
448448
protected def addDependency(symbol: Symbol): Unit
449449

450-
val seen = new mutable.HashSet[Type]
450+
// Avoid cycles by remembering both the types (testcase:
451+
// tests/run/enum-values.scala) and the symbols of named types (testcase:
452+
// tests/pos-java-interop/i13575) we've seen before.
453+
val seen = new mutable.HashSet[Symbol | Type]
451454
def traverse(tp: Type): Unit = if (!seen.contains(tp)) {
452455
seen += tp
453456
tp match {
454457
case tp: NamedType =>
455458
val sym = tp.symbol
456-
if (!sym.is(Package)) {
459+
if !seen.contains(sym) && !sym.is(Package) then
460+
seen += sym
457461
addDependency(sym)
458-
if (!sym.isClass)
459-
traverse(tp.info)
462+
if !sym.isClass then traverse(tp.info)
460463
traverse(tp.prefix)
461-
}
462464
case tp: ThisType =>
463465
traverse(tp.underlying)
464466
case tp: ConstantType =>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.lamoroso.example;
2+
3+
import java.util.Collections;
4+
import java.util.List;
5+
6+
public abstract class Builder<T extends Builder<T, R>, R> {
7+
8+
private List<String> pools;
9+
10+
public Builder<T, R> withPool(String... pools) {
11+
Collections.addAll(this.pools, pools);
12+
return this;
13+
}
14+
15+
public Builder<T, R> build(){return null;}
16+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.lamoroso.example;
2+
3+
public class Client {
4+
5+
public static Builder<?, ?> builder() {
6+
return null;
7+
}
8+
9+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.lamoroso.example;
2+
3+
public class RestClient {
4+
5+
private Object instance;
6+
7+
public RestClient(Object instance) {
8+
this.instance = instance;
9+
}
10+
11+
public static RestClientBuilder<?,?> builder() {
12+
return new RestClientBuilder();
13+
}
14+
15+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.lamoroso.example;
2+
3+
public class RestClientBuilder<T extends Builder<T, R>, R> {
4+
5+
private Builder<?, ?> wrappedBuilder;
6+
7+
protected RestClientBuilder() {
8+
this.wrappedBuilder = Client.builder();
9+
}
10+
11+
public RestClientBuilder<T, R> withPool(String... pools) {
12+
this.wrappedBuilder.withPool(pools);
13+
return this;
14+
}
15+
16+
public RestClient build() {
17+
return new RestClient(wrappedBuilder.build());
18+
}
19+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.lamoroso.example
2+
3+
object ScalaApp extends App {
4+
RestClient.builder().withPool("hello").build()
5+
}

0 commit comments

Comments
 (0)