Skip to content

Commit 7695b20

Browse files
Copilot CICopilot
andcommitted
Resolve a CS0104 ambiguity instead of guessing at its cause
CS0104 is the fifth most common Sandbox build error, and the runs it kills are the ones that report it more than once: all three runs in the cached corpus that hit it two or three times finished sandbox_inconclusive, while the eight that resolved it in one attempt mostly reached a candidate. A failed compile does not consume a semantic attempt, so an unresolved ambiguity quietly spends the build retries. The advice blamed a PlatformConfiguration import, which is one of the ten distinct ambiguities actually observed; the rest are Android.Widget, Microsoft.UI.Xaml, Microsoft.Maui.Platform and neighbouring Microsoft.Maui namespaces, for which that cause is simply absent. The diagnostic already names both candidates, so parse it and say which one a Sandbox page means: the cross-platform type over a platform one, the control over a non-control when both are cross-platform, and neither when there is no basis to choose. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 735ac9a2-7bec-4baa-ad19-c298e5bc795a
1 parent f9789e3 commit 7695b20

2 files changed

Lines changed: 230 additions & 1 deletion

File tree

.github/scripts/Replicate-Issue.Tests.ps1

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ BeforeAll {
107107
'Assert-GeneratedSandboxSources',
108108
'Get-ReplicationFixBaselineGreenCause',
109109
'Get-ReplicationMissingIdentifierEvidence',
110+
'Get-ReplicationAmbiguousTypeEvidence',
110111
'Get-ReplicationIdentifierSiteRank',
111112
'Set-ReplicationVerificationRunCount',
112113
'Test-ReplicationFixBaselineStillRed',
@@ -13495,3 +13496,102 @@ Describe 'A verified reproduction survives a fix-phase timeout' {
1349513496
}
1349613497
}
1349713498

13499+
Describe 'A CS0104 ambiguity is resolved, not re-described' {
13500+
# Fifth most common Sandbox build error in the corpus. Runs that resolved it
13501+
# in one attempt mostly reached CANDIDATE READY; all three that reported it
13502+
# two or three times finished sandbox_inconclusive. The standing advice
13503+
# blamed a PlatformConfiguration import, which is 1 of the 10 distinct
13504+
# ambiguities actually observed. Every fixture below is corpus-verbatim.
13505+
It 'recommends the cross-platform type over a platform one' -ForEach @(
13506+
@{ D = "CS0104: 'Button' is an ambiguous reference between 'Microsoft.Maui.Controls.Button' and 'Android.Widget.Button'"
13507+
Want = 'Microsoft.Maui.Controls.Button' }
13508+
@{ D = "CS0104: 'ContentView' is an ambiguous reference between 'Microsoft.Maui.Controls.ContentView' and 'Microsoft.Maui.Platform.ContentView'"
13509+
Want = 'Microsoft.Maui.Controls.ContentView' }
13510+
@{ D = "CS0104: 'Map' is an ambiguous reference between 'Microsoft.Maui.ApplicationModel.Map' and 'Microsoft.Maui.Controls.Maps.Map'"
13511+
Want = 'Microsoft.Maui.Controls.Maps.Map' }
13512+
@{ D = "CS0104: 'Page' is an ambiguous reference between 'Microsoft.Maui.Controls.Page' and 'Microsoft.UI.Xaml.Controls.Page'"
13513+
Want = 'Microsoft.Maui.Controls.Page' }
13514+
@{ D = "CS0104: 'Rect' is an ambiguous reference between 'Android.Graphics.Rect' and 'Microsoft.Maui.Graphics.Rect'"
13515+
Want = 'Microsoft.Maui.Graphics.Rect' }
13516+
@{ D = "CS0104: 'ScrollView' is an ambiguous reference between 'Microsoft.Maui.Controls.ScrollView' and 'Android.Widget.ScrollView'"
13517+
Want = 'Microsoft.Maui.Controls.ScrollView' }
13518+
@{ D = "CS0104: 'TextChangedEventArgs' is an ambiguous reference between 'Microsoft.Maui.Controls.TextChangedEventArgs' and 'Microsoft.UI.Xaml.Controls.TextChangedEventArgs'"
13519+
Want = 'Microsoft.Maui.Controls.TextChangedEventArgs' }
13520+
@{ D = "CS0104: 'Visibility' is an ambiguous reference between 'Microsoft.Maui.Visibility' and 'Microsoft.UI.Xaml.Visibility'"
13521+
Want = 'Microsoft.Maui.Visibility' }
13522+
) {
13523+
$evidence = Get-ReplicationAmbiguousTypeEvidence -Diagnostics $D
13524+
$evidence | Should -Match ([regex]::Escape("write '$Want' fully qualified"))
13525+
}
13526+
13527+
It 'prefers the control over a same-named PlatformConfiguration static class' {
13528+
# The one case the old advice did get right must not regress: this type
13529+
# lives *under* Microsoft.Maui.Controls, so a shortest-prefix test would
13530+
# invert the recommendation.
13531+
$evidence = Get-ReplicationAmbiguousTypeEvidence -Diagnostics (
13532+
"CS0104: 'ScrollView' is an ambiguous reference between " +
13533+
"'Microsoft.Maui.Controls.ScrollView' and " +
13534+
"'Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific.ScrollView'")
13535+
$evidence | Should -Match ([regex]::Escape(
13536+
"write 'Microsoft.Maui.Controls.ScrollView' fully qualified"))
13537+
}
13538+
13539+
It 'picks the control when both are cross-platform but only one is a control' {
13540+
# ApplicationModel.Map is the launcher API; only Controls.Maps.Map can
13541+
# be placed on a page, which is what a Sandbox scenario is doing.
13542+
$evidence = Get-ReplicationAmbiguousTypeEvidence -Diagnostics (
13543+
"CS0104: 'Map' is an ambiguous reference between " +
13544+
"'Microsoft.Maui.ApplicationModel.Map' and 'Microsoft.Maui.Controls.Maps.Map'")
13545+
$evidence | Should -Match ([regex]::Escape(
13546+
"write 'Microsoft.Maui.Controls.Maps.Map' fully qualified"))
13547+
}
13548+
13549+
It 'refuses to choose when both candidates are cross-platform' {
13550+
$evidence = Get-ReplicationAmbiguousTypeEvidence -Diagnostics (
13551+
"CS0104: 'Font' is an ambiguous reference between " +
13552+
"'Microsoft.Maui.Graphics.Font' and 'Microsoft.Maui.Font'")
13553+
$evidence | Should -Match 'do not assume'
13554+
$evidence | Should -Not -Match 'fully qualified,'
13555+
}
13556+
13557+
It 'treats Microsoft.Maui.Platform as platform, not cross-platform' {
13558+
# Synthetic, not corpus-verbatim: every observed Platform conflict is
13559+
# against a Controls type, which the control rule already resolves. The
13560+
# classification is still asserted here because Microsoft.Maui.Platform
13561+
# is platform-only by definition, and without this the prefix would be
13562+
# indistinguishable from its own absence.
13563+
$evidence = Get-ReplicationAmbiguousTypeEvidence -Diagnostics (
13564+
"CS0104: 'Insets' is an ambiguous reference between " +
13565+
"'Microsoft.Maui.Platform.Insets' and 'Microsoft.Maui.Graphics.Insets'")
13566+
$evidence | Should -Match ([regex]::Escape(
13567+
"write 'Microsoft.Maui.Graphics.Insets' fully qualified"))
13568+
}
13569+
13570+
It 'says nothing when no ambiguity is present' {
13571+
Get-ReplicationAmbiguousTypeEvidence -Diagnostics (
13572+
"MainPage.xaml.cs(33,11): error CS0103: The name 'Foo' does not exist"
13573+
) | Should -BeNullOrEmpty
13574+
Get-ReplicationAmbiguousTypeEvidence -Diagnostics '' | Should -BeNullOrEmpty
13575+
}
13576+
13577+
It 'reports each distinct ambiguity once and stays bounded' {
13578+
$d = @(
13579+
"CS0104: 'Button' is an ambiguous reference between 'Microsoft.Maui.Controls.Button' and 'Android.Widget.Button'",
13580+
"CS0104: 'Button' is an ambiguous reference between 'Microsoft.Maui.Controls.Button' and 'Android.Widget.Button'",
13581+
"CS0104: 'Page' is an ambiguous reference between 'Microsoft.Maui.Controls.Page' and 'Microsoft.UI.Xaml.Controls.Page'",
13582+
"CS0104: 'Rect' is an ambiguous reference between 'Android.Graphics.Rect' and 'Microsoft.Maui.Graphics.Rect'",
13583+
"CS0104: 'Visibility' is an ambiguous reference between 'Microsoft.Maui.Visibility' and 'Microsoft.UI.Xaml.Visibility'"
13584+
) -join ' '
13585+
$evidence = Get-ReplicationAmbiguousTypeEvidence -Diagnostics $d
13586+
([regex]::Matches($evidence, "is ambiguous between")).Count | Should -Be 3
13587+
([regex]::Matches($evidence, "'Button' is ambiguous")).Count | Should -Be 1
13588+
}
13589+
13590+
It 'is wired into the Sandbox build feedback the agent actually reads' {
13591+
$source = Get-Content -Raw -LiteralPath (
13592+
Join-Path $PSScriptRoot 'Replicate-Issue.ps1')
13593+
$source | Should -Match 'Get-ReplicationAmbiguousTypeEvidence `\r?\n\s*-Diagnostics \$prepareDiagnostics'
13594+
$source | Should -Match '\$ambiguityNote'
13595+
}
13596+
}
13597+

.github/scripts/Replicate-Issue.ps1

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,132 @@ function Get-ReplicationIdentifierSiteRank {
10801080
return 2
10811081
}
10821082

1083+
function Get-ReplicationAmbiguousTypeEvidence {
1084+
<#
1085+
.SYNOPSIS
1086+
Names the two types a CS0104 ambiguity is actually between, and
1087+
which one a Sandbox page almost certainly means.
1088+
1089+
.DESCRIPTION
1090+
CS0104 is the fifth most common Sandbox build error in the cached
1091+
corpus. Its cost is not the first occurrence but the repeat: of the
1092+
12 runs that hit one, the 8 that resolved it within a single attempt
1093+
mostly reached CANDIDATE READY, while all 3 that reported it two or
1094+
three times finished sandbox_inconclusive. A compile failure does
1095+
not consume a semantic attempt, so an unresolved ambiguity burns the
1096+
build retries and the run dies having never reached the device.
1097+
1098+
The advice it was given assumed one specific cause: an import of
1099+
Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific or a
1100+
sibling, each of which declares a static class sharing a control's
1101+
name. That is real, but it is 1 of the 10 distinct ambiguities in
1102+
the corpus. The other nine are Android.Widget, Microsoft.UI.Xaml,
1103+
Microsoft.Maui.Platform and neighbouring Microsoft.Maui namespaces,
1104+
for which "drop the platform-specific using" names the wrong cause -
1105+
the same misdirection already documented for element-text failures,
1106+
where feedback told the author to change the one thing that worked.
1107+
1108+
The diagnostic already carries the answer: it names both candidates
1109+
in full. So resolve rather than re-describe. A Sandbox page is
1110+
cross-platform MAUI UI, so when exactly one candidate sits in a
1111+
cross-platform MAUI namespace and the other in a platform or
1112+
interop one, the cross-platform type is the intended one and is
1113+
named as such. When both are cross-platform - 'Font' is ambiguous
1114+
between Microsoft.Maui.Graphics.Font and Microsoft.Maui.Font - there
1115+
is no basis to choose, so both are reported and neither is
1116+
recommended. Guessing there would be exactly the confident wrong
1117+
answer this phase exists to prevent.
1118+
#>
1119+
param(
1120+
[Parameter(Mandatory = $true)][AllowEmptyString()][string]$Diagnostics,
1121+
[int]$MaximumAmbiguities = 3
1122+
)
1123+
1124+
if ([string]::IsNullOrWhiteSpace($Diagnostics)) {
1125+
return ''
1126+
}
1127+
1128+
# A type is cross-platform when it sits under Microsoft.Maui and is not one
1129+
# of the two Maui namespaces that are platform-only. Every other namespace
1130+
# an ambiguity names - Android, Microsoft.UI.Xaml, UIKit, Java - is already
1131+
# not cross-platform by that test, so listing it would be configuration
1132+
# whose removal no test could detect. Ordered longest-prefix-first is not
1133+
# needed once the set is this small, but PlatformConfiguration must still be
1134+
# recognised: it sits under Microsoft.Maui.Controls and would otherwise be
1135+
# read as the control itself.
1136+
$platformPrefixes = @(
1137+
'Microsoft.Maui.Controls.PlatformConfiguration.',
1138+
'Microsoft.Maui.Platform.'
1139+
)
1140+
# One prefix suffices: Microsoft.Maui.Controls and Microsoft.Maui.Graphics
1141+
# are both under it, and listing them separately is configuration that no
1142+
# test can distinguish from its own absence.
1143+
$portablePrefixes = @(
1144+
'Microsoft.Maui.'
1145+
)
1146+
1147+
$isPlatform = {
1148+
param([string]$Type)
1149+
foreach ($prefix in $platformPrefixes) {
1150+
if ($Type.StartsWith($prefix, [System.StringComparison]::Ordinal)) { return $true }
1151+
}
1152+
return $false
1153+
}
1154+
$isPortable = {
1155+
param([string]$Type)
1156+
if (& $isPlatform $Type) { return $false }
1157+
foreach ($prefix in $portablePrefixes) {
1158+
if ($Type.StartsWith($prefix, [System.StringComparison]::Ordinal)) { return $true }
1159+
}
1160+
return $false
1161+
}
1162+
1163+
$lines = New-Object System.Collections.Generic.List[string]
1164+
$seen = New-Object System.Collections.Generic.HashSet[string]
1165+
$matches = [regex]::Matches(
1166+
[string]$Diagnostics,
1167+
"CS0104: '([^']+)' is an ambiguous reference between '([^']+)' and '([^']+)'")
1168+
1169+
foreach ($match in $matches) {
1170+
$name = $match.Groups[1].Value
1171+
$first = $match.Groups[2].Value
1172+
$second = $match.Groups[3].Value
1173+
if (-not $seen.Add($name)) { continue }
1174+
if ($lines.Count -ge $MaximumAmbiguities) { break }
1175+
1176+
$firstPortable = & $isPortable $first
1177+
$secondPortable = & $isPortable $second
1178+
# Between two cross-platform candidates there is still one honest
1179+
# discriminator: a Sandbox page authors UI, so a type under
1180+
# Microsoft.Maui.Controls is the control and the other is not.
1181+
# 'Map' is ambiguous between the ApplicationModel *launcher* and the
1182+
# Controls.Maps *control*, and only the control can be placed on a page.
1183+
# 'Font' has no such discriminator - Microsoft.Maui.Graphics.Font and
1184+
# Microsoft.Maui.Font are both plain cross-platform types - so it is
1185+
# left unresolved rather than guessed.
1186+
$controlsPrefix = 'Microsoft.Maui.Controls.'
1187+
if ($firstPortable -and $secondPortable) {
1188+
$firstControl = $first.StartsWith($controlsPrefix, [System.StringComparison]::Ordinal)
1189+
$secondControl = $second.StartsWith($controlsPrefix, [System.StringComparison]::Ordinal)
1190+
if ($firstControl -and -not $secondControl) { $secondPortable = $false }
1191+
elseif ($secondControl -and -not $firstControl) { $firstPortable = $false }
1192+
}
1193+
if ($firstPortable -and -not $secondPortable) {
1194+
$lines.Add(("'{0}' is ambiguous between '{1}' and '{2}'; a Sandbox page is cross-platform MAUI UI, so write '{1}' fully qualified, or alias it with 'using {3} = {1};', rather than removing either using." -f $name, $first, $second, ('M' + $name)))
1195+
} elseif ($secondPortable -and -not $firstPortable) {
1196+
$lines.Add(("'{0}' is ambiguous between '{1}' and '{2}'; a Sandbox page is cross-platform MAUI UI, so write '{2}' fully qualified, or alias it with 'using {3} = {2};', rather than removing either using." -f $name, $first, $second, ('M' + $name)))
1197+
} else {
1198+
$lines.Add(("'{0}' is ambiguous between '{1}' and '{2}'; both are cross-platform MAUI namespaces, so fully qualify whichever one the scenario needs - do not assume." -f $name, $first, $second))
1199+
}
1200+
}
1201+
1202+
if ($lines.Count -eq 0) {
1203+
return ''
1204+
}
1205+
1206+
return ('The diagnostic already names both candidates. ' + ($lines -join ' '))
1207+
}
1208+
10831209
function Get-ReplicationMissingIdentifierEvidence {
10841210
<#
10851211
.SYNOPSIS
@@ -7543,10 +7669,13 @@ $sandboxFailureSummary
75437669
elseif ($sandboxFailureSummary -match '(?i)Preparing the Sandbox app failed') {
75447670
$prepareDiagnostics = Get-ReplicationCompilerDiagnostics -LogPath $prepareLog
75457671
if ($prepareDiagnostics) {
7672+
$ambiguityEvidence = Get-ReplicationAmbiguousTypeEvidence `
7673+
-Diagnostics $prepareDiagnostics
7674+
$ambiguityNote = if ($ambiguityEvidence) { "`n$ambiguityEvidence" } else { '' }
75467675
$sandboxFailureSummary = @"
75477676
The Sandbox build failed with these compiler diagnostics: $prepareDiagnostics
75487677
Fix the authored Sandbox source so it compiles. This repository builds with warnings as errors. Resolve ambiguous type references such as ILayout by fully qualifying the intended type, match the exact overload signature of the API you call, and give collection expressions a constructible target type.
7549-
A CS0104 ambiguity on VisualElement, Page, Application, Entry or similar usually means the file imports Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific, AndroidSpecific or WindowsSpecific, each of which declares its own static class with that name. Drop the platform-specific using and call the platform helper through its full namespace instead. Do not guess at member names on those helpers; use only members you have confirmed in this repository's source.
7678+
A CS0104 ambiguity on VisualElement, Page, Application, Entry or similar usually means the file imports Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific, AndroidSpecific or WindowsSpecific, each of which declares its own static class with that name. Drop the platform-specific using and call the platform helper through its full namespace instead. Do not guess at member names on those helpers; use only members you have confirmed in this repository's source.$ambiguityNote
75507679
75517680
$sandboxFailureSummary
75527681
"@

0 commit comments

Comments
 (0)