diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 0a76ff9f240b..7668498845c2 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -1726,31 +1726,36 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w * @note We do not admit singleton types in or-types as lubs. */ def lub(tp1: Type, tp2: Type, canConstrain: Boolean = false): Type = /*>|>*/ trace(s"lub(${tp1.show}, ${tp2.show}, canConstrain=$canConstrain)", subtyping, show = true) /*<|<*/ { - if (tp1 eq tp2) return tp1 - if (!tp1.exists) return tp1 - if (!tp2.exists) return tp2 - if ((tp1 isRef AnyClass) || (tp1 isRef AnyKindClass) || (tp2 isRef NothingClass)) return tp1 - if ((tp2 isRef AnyClass) || (tp2 isRef AnyKindClass) || (tp1 isRef NothingClass)) return tp2 - val atoms1 = tp1.atoms - if (atoms1.nonEmpty && !widenInUnions) { - val atoms2 = tp2.atoms - if (atoms2.nonEmpty) { - if (atoms1.subsetOf(atoms2)) return tp2 - if (atoms2.subsetOf(atoms1)) return tp1 - if ((atoms1 & atoms2).isEmpty) return orType(tp1, tp2) - } - } - val t1 = mergeIfSuper(tp1, tp2, canConstrain) - if (t1.exists) return t1 + if (tp1 eq tp2) tp1 + else if (!tp1.exists) tp1 + else if (!tp2.exists) tp2 + else if ((tp1 isRef AnyClass) || (tp1 isRef AnyKindClass) || (tp2 isRef NothingClass)) tp1 + else if ((tp2 isRef AnyClass) || (tp2 isRef AnyKindClass) || (tp1 isRef NothingClass)) tp2 + else { + def mergedLub: Type = { + val atoms1 = tp1.atoms + if (atoms1.nonEmpty && !widenInUnions) { + val atoms2 = tp2.atoms + if (atoms2.nonEmpty) { + if (atoms1.subsetOf(atoms2)) return tp2 + if (atoms2.subsetOf(atoms1)) return tp1 + if ((atoms1 & atoms2).isEmpty) return orType(tp1, tp2) + } + } + val t1 = mergeIfSuper(tp1, tp2, canConstrain) + if (t1.exists) return t1 - val t2 = mergeIfSuper(tp2, tp1, canConstrain) - if (t2.exists) return t2 + val t2 = mergeIfSuper(tp2, tp1, canConstrain) + if (t2.exists) return t2 - def widen(tp: Type) = if (widenInUnions) tp.widen else tp.widenIfUnstable - val tp1w = widen(tp1) - val tp2w = widen(tp2) - if ((tp1 ne tp1w) || (tp2 ne tp2w)) lub(tp1w, tp2w) - else orType(tp1w, tp2w) // no need to check subtypes again + def widen(tp: Type) = if (widenInUnions) tp.widen else tp.widenIfUnstable + val tp1w = widen(tp1) + val tp2w = widen(tp2) + if ((tp1 ne tp1w) || (tp2 ne tp2w)) lub(tp1w, tp2w) + else orType(tp1w, tp2w) // no need to check subtypes again + } + mergedLub + } } /** The least upper bound of a list of types */ diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index b4398b171427..2d4d611843af 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -216,8 +216,11 @@ object Applications { /** A wrapper indicating that its argument is an application of an extension method. */ class ExtMethodApply(app: Tree)(implicit @constructorOnly src: SourceFile) - extends IntegratedTypeArgs(app) - + extends IntegratedTypeArgs(app) { + overwriteType(WildcardType) + // ExtMethodApply always has wildcard type in order not to prompt any further adaptations + // such as eta expansion before the method is fully applied. + } } trait Applications extends Compatibility { self: Typer with Dynamic => diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 99fb98fe6b61..310c93befda9 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -1348,7 +1348,7 @@ trait Implicits { self: Typer => } else { val returned = - if (cand.isExtension) new Applications.ExtMethodApply(adapted).withType(adapted.tpe) + if (cand.isExtension) Applications.ExtMethodApply(adapted) else adapted SearchSuccess(returned, ref, cand.level)(ctx.typerState, ctx.gadt) } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 29294dd68826..60c074f82955 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3021,9 +3021,7 @@ class Typer extends Namer val app = tryExtension(nestedCtx) if (!app.isEmpty && !nestedCtx.reporter.hasErrors) { nestedCtx.typerState.commit() - return new ExtMethodApply(app).withType(WildcardType) - // Use wildcard type in order not to prompt any further adaptations such as eta expansion - // before the method is fully applied. + return ExtMethodApply(app) } case _ => } diff --git a/tests/pos/combine.scala b/tests/pos/combine.scala new file mode 100644 index 000000000000..6c64da676f0f --- /dev/null +++ b/tests/pos/combine.scala @@ -0,0 +1,10 @@ +trait Semigroup[A] { + def (x: A) combine (y: A): A +} +delegate for Semigroup[Int] = ??? +delegate [A, B] for Semigroup[(A, B)] given Semigroup[A], Semigroup[B] = ??? +object Test extends App { + ((1, 1)) combine ((2, 2)) // doesn't compile + ((1, 1): (Int, Int)) combine (2, 2) // compiles + //the error that compiler spat out was "value combine is not a member of ((Int, Int)) => (Int, Int)". what's +} \ No newline at end of file