···479479 location: SrcSpan,
480480 },
481481 UnqualifiedImport(UnqualifiedImport<'a>),
482482+ /// The label of a labelled argument in a function call.
482483 Label {
483484 location: SrcSpan,
484484- /// The type of the labelled argument value (used for hover).
485485- type_: std::sync::Arc<Type>,
485485+ /// The type of the labelled argument's value (used for hover).
486486+ field_type: std::sync::Arc<Type>,
487487+ },
488488+ /// A record field label at its definition in a custom type variant.
489489+ RecordLabelDefinition {
490490+ location: SrcSpan,
491491+ /// The type of the field (used for hover).
492492+ field_type: std::sync::Arc<Type>,
486493 label: EcoString,
487487- /// The record type the label belongs to, used for go-to-definition,
488488- /// find-references and rename. `None` when it can't be determined.
489489- owner: Option<LabelOwner>,
494494+ /// The name of the custom type this field belongs to. The type is
495495+ /// being defined in the module being analysed, so only its name is
496496+ /// needed.
497497+ type_name: EcoString,
498498+ },
499499+ /// A record field label used in a record constructor call or pattern, or
500500+ /// in a record update.
501501+ RecordLabelUsage {
502502+ location: SrcSpan,
503503+ /// The type of the field's value (used for hover).
504504+ field_type: std::sync::Arc<Type>,
505505+ label: EcoString,
506506+ /// The record type the field belongs to.
507507+ record_type: std::sync::Arc<Type>,
508508+ /// The name of the variant the field was used with.
509509+ variant: EcoString,
510510+ },
511511+ /// The label of a record field access: `record.label`.
512512+ RecordAccessLabel {
513513+ location: SrcSpan,
514514+ /// The type of the field (used for hover).
515515+ field_type: std::sync::Arc<Type>,
516516+ label: EcoString,
517517+ /// The record type the field belongs to.
518518+ record_type: std::sync::Arc<Type>,
519519+ /// The documentation of the field (used for hover).
520520+ documentation: Option<EcoString>,
490521 },
491522 ModuleName {
492523 location: SrcSpan,
···503534 ModuleImport(&'a TypedImport),
504535 ModuleCustomType(&'a TypedCustomType),
505536 ModuleTypeAlias(&'a TypedTypeAlias),
506506-}
507507-508508-/// The record type a field label belongs to. Used to resolve go-to-definition,
509509-/// find-references and rename for record fields.
510510-#[derive(Debug, Clone, PartialEq)]
511511-pub enum LabelOwner {
512512- /// A label usage (`record.field`, a labelled argument or pattern, a record
513513- /// update) where the value's type is known. The type carries the module
514514- /// and name it belongs to.
515515- Usage {
516516- type_: std::sync::Arc<Type>,
517517- constructor: EcoString,
518518- },
519519- /// A label at its declaration in a custom type. The type is being defined
520520- /// in the current module, so only its name is needed.
521521- Definition {
522522- type_name: EcoString,
523523- constructor: EcoString,
524524- },
525537}
526538527539impl<'a> Located<'a> {
···537549 })
538550 }
539551540540- /// Looks up the definition location of a record field label using
541541- /// the pre-computed label reference map.
552552+ /// Looks up the location at which a record field label was defined, using
553553+ /// the label definitions gathered during analysis.
542554 fn label_definition_location(
543555 &self,
544556 importable_modules: &'a im::HashMap<EcoString, type_::ModuleInterface>,
545557 record_type: &Arc<Type>,
546558 label: &EcoString,
547547- constructor: Option<&EcoString>,
559559+ variant: Option<&EcoString>,
548560 ) -> Option<DefinitionLocation> {
549561 let (module_name, type_name) = record_type.named_type_name()?;
550562 let module = importable_modules.get(&module_name)?;
···553565 type_name,
554566 label: label.clone(),
555567 };
556556- let references = module.references.label_references.get(&key)?;
557557- let definition = references.iter().find(|r| {
558558- r.kind == reference::ReferenceKind::Definition
559559- && match (&r.constructor, constructor) {
560560- (Some(a), Some(b)) => a == b,
561561- _ => true,
562562- }
563563- })?;
568568+ let definitions = module.references.label_definitions.get(&key)?;
569569+ // A label can be defined in multiple variants of the same type. If we
570570+ // know which variant the label was used with we jump to its
571571+ // definition in that variant. Otherwise the label comes from a
572572+ // `record.field` access, which works across all the variants defining
573573+ // it, so we jump to the first definition.
574574+ let definition = match variant {
575575+ Some(variant) => definitions
576576+ .iter()
577577+ .find(|definition| &definition.variant == variant)?,
578578+ None => definitions.first()?,
579579+ };
564580 Some(DefinitionLocation {
565581 module: Some(module_name),
566582 span: definition.location,
···580596 }),
581597 Self::Statement(statement) => statement.definition_location(),
582598 Self::FunctionBody(statement) => None,
583583- Self::Expression {
584584- expression: TypedExpr::RecordAccess { record, label, .. },
585585- ..
586586- } => self.label_definition_location(importable_modules, &record.type_(), label, None),
587599 Self::Expression { expression, .. } => expression.definition_location(),
588600589601 Self::ModuleImport(import) => Some(DefinitionLocation {
···631643 }),
632644 Self::Arg(_) => None,
633645 Self::Annotation { type_, .. } => self.type_location(importable_modules, type_.clone()),
634634- Self::Label {
635635- owner:
636636- Some(LabelOwner::Usage {
637637- type_: record_type,
638638- constructor,
639639- }),
646646+ Self::Label { .. } => None,
647647+ Self::RecordLabelUsage {
648648+ record_type,
640649 label,
650650+ variant,
641651 ..
642652 } => self.label_definition_location(
643653 importable_modules,
644654 record_type,
645655 label,
646646- Some(constructor),
656656+ Some(variant),
647657 ),
648648- // Already at the declaration; go-to-definition jumps to itself.
649649- Self::Label {
650650- owner: Some(LabelOwner::Definition { .. }),
651651- location,
652652- ..
653653- } => Some(DefinitionLocation {
658658+ Self::RecordAccessLabel {
659659+ record_type, label, ..
660660+ } => self.label_definition_location(importable_modules, record_type, label, None),
661661+ // Already at the definition; go-to-definition jumps to itself.
662662+ Self::RecordLabelDefinition { location, .. } => Some(DefinitionLocation {
654663 module: None,
655664 span: *location,
656665 }),
657657- Self::Label { .. } => None,
658666 Self::TypeVariable { .. } => None,
659667 Self::ModuleName { module_name, .. } => Some(DefinitionLocation {
660668 module: Some(module_name.clone()),
···672680 Located::Statement(statement) => Some(statement.type_()),
673681 Located::Expression { expression, .. } => Some(expression.type_()),
674682 Located::Arg(arg) => Some(arg.type_.clone()),
675675- Located::Label { type_, .. } | Located::Annotation { type_, .. } => Some(type_.clone()),
683683+ Located::Label { field_type, .. }
684684+ | Located::RecordLabelDefinition { field_type, .. }
685685+ | Located::RecordLabelUsage { field_type, .. }
686686+ | Located::RecordAccessLabel { field_type, .. } => Some(field_type.clone()),
687687+ Located::Annotation { type_, .. } => Some(type_.clone()),
676688 Located::Constant(constant) => Some(constant.type_()),
677689 Located::ClauseGuard(guard) => Some(guard.type_()),
678690
···177177178178pub type ReferenceMap = HashMap<(EcoString, EcoString), Vec<Reference>>;
179179180180-#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
180180+/// A use of a record field label: a labelled argument in a record constructor
181181+/// call or pattern, a record update argument, or a `record.field` access.
182182+#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
181183pub struct LabelReference {
182184 /// The location of the label. For a shorthand (`label:`) this spans the
183185 /// whole `label:`, mirroring how variable references record label
184186 /// shorthands. For everything else it is just the label itself.
185187 pub location: SrcSpan,
186186- pub kind: ReferenceKind,
187187- /// The constructor this label belongs to. `None` for usages where the
188188- /// constructor is unknown (e.g. `record.field`).
189189- pub constructor: Option<EcoString>,
190190- /// Whether the label was written using the shorthand syntax (`label:`).
191191- /// Renaming the field then has to expand it so the value keeps its name:
192192- /// `wibble:` becomes `wobble: wibble`.
193193- pub shorthand: bool,
188188+ pub syntax: LabelSyntax,
189189+}
190190+191191+/// The syntax used to write a record field label where it is used.
192192+#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
193193+pub enum LabelSyntax {
194194+ /// The label is written out on its own, as in `Wibble(label: value)` or
195195+ /// `record.label`, so renaming it is a simple replacement.
196196+ Longhand,
197197+ /// The label shorthand syntax (`label:`), which stands for both the label
198198+ /// and a variable with the same name. Renaming the field then has to
199199+ /// expand it so the value keeps its name: `wibble:` becomes
200200+ /// `wobble: wibble`.
201201+ Shorthand,
202202+}
203203+204204+/// The location at which a record field label is defined in one of the
205205+/// variants of a custom type.
206206+#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
207207+pub struct LabelDefinition {
208208+ pub location: SrcSpan,
209209+ /// The name of the variant this label is defined in.
210210+ pub variant: EcoString,
194211}
195212196213/// Identifies a record field label within a custom type, used to look up the
···278295 /// The locations of the references to each record field label in this
279296 /// module, used for renaming and go-to reference.
280297 pub label_references: HashMap<RecordLabel, Vec<LabelReference>>,
298298+ /// The locations at which each record field label is defined, one per
299299+ /// variant that defines it, used for renaming and go-to definition.
300300+ pub label_definitions: HashMap<RecordLabel, Vec<LabelDefinition>>,
281301282302 /// This map is used to access the nodes of modules that were not
283303 /// aliased, given their name.
···639659 .push(reference);
640660 }
641661642642- /// Registers a reference to a record field label.
662662+ /// Registers a use of a record field label.
643663 ///
644664 /// `type_` is the `(module, name)` of the type the label belongs to, as
645665 /// returned by [`Type::named_type_name`].
···648668 type_: (EcoString, EcoString),
649669 label: EcoString,
650670 location: SrcSpan,
651651- kind: ReferenceKind,
652652- constructor: Option<EcoString>,
653653- shorthand: bool,
671671+ syntax: LabelSyntax,
654672 ) {
655673 let (type_module, type_name) = type_;
656674 self.label_references
···660678 label,
661679 })
662680 .or_default()
663663- .push(LabelReference {
664664- location,
665665- kind,
666666- constructor,
667667- shorthand,
668668- });
681681+ .push(LabelReference { location, syntax });
682682+ }
683683+684684+ /// Registers the definition of a record field label in one of the
685685+ /// variants of a custom type.
686686+ ///
687687+ /// `type_` is the `(module, name)` of the type being defined, as returned
688688+ /// by [`Type::named_type_name`].
689689+ pub fn register_label_definition(
690690+ &mut self,
691691+ type_: (EcoString, EcoString),
692692+ label: EcoString,
693693+ location: SrcSpan,
694694+ variant: EcoString,
695695+ ) {
696696+ let (type_module, type_name) = type_;
697697+ self.label_definitions
698698+ .entry(RecordLabel {
699699+ type_module,
700700+ type_name,
701701+ label,
702702+ })
703703+ .or_default()
704704+ .push(LabelDefinition { location, variant });
669705 }
670706671707 /// Like `register_type_reference`, but doesn't modify `self.type_references`.
···2020 build::Target,
2121 exhaustiveness::{self, CompileCaseResult, CompiledCase, Reachability},
2222 parse::{LiteralFloatValue, PatternPosition},
2323- reference::ReferenceKind,
2323+ reference::{LabelSyntax, ReferenceKind},
2424};
2525use ecow::eco_format;
2626use hexpm::version::{LowestVersion, Version};
···12271227 }
1228122812291229 self.purity = self.purity.merge(fun.called_function_purity());
12301230-12311231- // Register field label references for record constructor calls.
12321232- if fun.is_record_constructor_function()
12331233- && let Some(type_name) = type_.named_type_name()
12341234- {
12351235- let constructor_name = fun.name();
12361236- for arg in &arguments {
12371237- if let (Some(label), Some(label_location)) = (&arg.label, arg.label_location()) {
12381238- self.environment.references.register_label_reference(
12391239- type_name.clone(),
12401240- label.clone(),
12411241- label_location,
12421242- ReferenceKind::Unqualified,
12431243- constructor_name.clone(),
12441244- arg.uses_label_shorthand(),
12451245- );
12461246- }
12471247- }
12481248- }
1249123012501231 TypedExpr::Call {
12511232 location,
···30082989 ) -> Result<TypedExpr, Error> {
30092990 let record = Box::new(record);
30102991 let record_type = record.type_();
29922992+ let type_name = record_type.named_type_name();
30112993 let RecordAccessor {
30122994 index,
30132995 label,
30142996 type_,
30152997 documentation,
30162998 } = self.infer_known_record_access(
30173017- record_type.clone(),
29992999+ record_type,
30183000 record.location(),
30193001 usage,
30203002 label_location,
30213003 label,
30223004 )?;
30233023- if let Some(type_) = record_type.named_type_name() {
30053005+ if let Some(type_name) = type_name {
30243006 self.environment.references.register_label_reference(
30253025- type_,
30073007+ type_name,
30263008 label.clone(),
30273009 label_location,
30283028- ReferenceKind::Unqualified,
30293029- None,
30303030- false,
30103010+ LabelSyntax::Longhand,
30313011 );
30323012 }
30333013 Ok(TypedExpr::RecordAccess {
···32953275 self.problems.error(convert_unify_error(error, *location));
32963276 };
3297327732983298- if let Some(type_) = return_type.named_type_name() {
32783278+ if let Some(type_name) = return_type.named_type_name() {
32993279 self.environment.references.register_label_reference(
33003300- type_,
32803280+ type_name,
33013281 label.clone(),
33023282 argument.label_location(),
33033303- ReferenceKind::Unqualified,
33043304- Some(variant.constructor_name.clone()),
33053305- argument.uses_label_shorthand(),
32833283+ argument.label_syntax(),
33063284 );
33073285 }
33083286···35763554 arguments: arguments_types,
35773555 return_type,
35783556 field_map,
35793579- constructor_name: name.clone(),
35803557 });
35813558 }
35823559···35893566 arguments: arguments_types,
35903567 return_type,
35913568 field_map,
35923592- constructor_name: name.clone(),
35933569 });
35943570 }
35953571···4129410541304106 let mut final_arguments = base_arguments;
41314107 for argument in arguments {
41324132- // Captured before `argument.value` is moved below, so they
41334133- // are still available when we register the label reference.
41344134- let shorthand = argument.uses_label_shorthand();
41084108+ let syntax = argument.label_syntax();
41354109 let label_location = argument.label_location();
41364136- if shorthand {
41104110+ if argument.uses_label_shorthand() {
41374111 self.track_feature_usage(
41384112 FeatureKind::LabelShorthandSyntax,
41394113 argument.location,
···41714145 return self.new_invalid_constant(location);
41724146 }
4173414741744174- if let Some(type_) = expected_type.named_type_name() {
41484148+ if let Some(type_name) = expected_type.named_type_name() {
41754149 self.environment.references.register_label_reference(
41764176- type_,
41504150+ type_name,
41774151 label.clone(),
41784152 label_location,
41794179- ReferenceKind::Unqualified,
41804180- Some(constructor_tag.clone()),
41814181- shorthand,
41534153+ syntax,
41824154 );
41834155 }
41844156···45194491 // Register a reference to each labelled field so the language server can
45204492 // offer go-to-definition, find-references and rename on record fields. We
45214493 // do this before adding back the ignored arguments below, as those are
45224522- // synthetic placeholders without a real value.
45234523- if let Some(type_) = expected_return.named_type_name() {
44944494+ // synthetic placeholders without a real value: their labels are
44954495+ // registered using the locations captured before the values were
44964496+ // discarded.
44974497+ if let Some(type_name) = expected_return.named_type_name() {
45244498 for argument in &typed_arguments {
45254525- if let (Some(label), Some(label_location)) =
45264526- (&argument.label, argument.label_location())
44994499+ if let Some(label) = &argument.label
45004500+ && let Some(label_location) = argument.label_location()
45014501+ {
45024502+ self.environment.references.register_label_reference(
45034503+ type_name.clone(),
45044504+ label.clone(),
45054505+ label_location,
45064506+ argument.label_syntax(),
45074507+ );
45084508+ }
45094509+ }
45104510+45114511+ for argument in &ignored_labelled_arguments {
45124512+ if let Some(label) = &argument.label
45134513+ && let Some(label_location) = argument.label_location
45144514+ && argument.implicit.is_none()
45274515 {
45284516 self.environment.references.register_label_reference(
45294529- type_.clone(),
45174517+ type_name.clone(),
45304518 label.clone(),
45314519 label_location,
45324532- ReferenceKind::Unqualified,
45334533- Some(name.clone()),
45344534- argument.uses_label_shorthand(),
45204520+ argument.syntax,
45354521 );
45364522 }
45374523 }
···45494535 label,
45504536 location,
45514537 implicit,
45384538+ ..
45524539 } in ignored_labelled_arguments
45534540 {
45544541 typed_arguments.push(CallArg {
···50114998 })
50124999 .collect();
5013500050015001+ // Register a reference to each labelled field so the language server can
50025002+ // offer go-to-definition, find-references and rename on record fields. We
50035003+ // do this before adding back the ignored arguments below, as those are
50045004+ // synthetic placeholders without a real value: their labels are
50055005+ // registered using the locations captured before the values were
50065006+ // discarded.
50075007+ if fun.is_record_constructor_function()
50085008+ && let Some(type_name) = return_type.named_type_name()
50095009+ {
50105010+ for argument in &typed_arguments {
50115011+ if let Some(label) = &argument.label
50125012+ && let Some(label_location) = argument.label_location()
50135013+ {
50145014+ self.environment.references.register_label_reference(
50155015+ type_name.clone(),
50165016+ label.clone(),
50175017+ label_location,
50185018+ argument.label_syntax(),
50195019+ );
50205020+ }
50215021+ }
50225022+50235023+ for argument in &ignored_labelled_arguments {
50245024+ if let Some(label) = &argument.label
50255025+ && let Some(label_location) = argument.label_location
50265026+ && argument.implicit.is_none()
50275027+ {
50285028+ self.environment.references.register_label_reference(
50295029+ type_name.clone(),
50305030+ label.clone(),
50315031+ label_location,
50325032+ argument.syntax,
50335033+ );
50345034+ }
50355035+ }
50365036+ }
50375037+50145038 // Now if we had supplied less arguments than required and some of those
50155039 // were labelled, in the previous step we would have got rid of those
50165040 // _before_ typing.
···50235047 label,
50245048 location,
50255049 implicit,
50505050+ ..
50265051 } in ignored_labelled_arguments
50275052 {
50285053 typed_arguments.push(CallArg {
···55085533 }
55095534 }
5510553555115511- fn fault_tolerant_match_function_type<A>(
55365536+ fn fault_tolerant_match_function_type<A: HasLocation>(
55125537 &mut self,
55135538 has_labelled_arity_error: bool,
55145539 call_kind: CallKind,
···55925617 label: argument.label.clone(),
55935618 location: argument.location(),
55945619 implicit: argument.implicit,
56205620+ label_location: argument.label_location(),
56215621+ syntax: argument.label_syntax(),
55955622 })
55965623 .collect_vec();
55975624···56235650 label: Option<EcoString>,
56245651 location: SrcSpan,
56255652 implicit: Option<ImplicitCallArgOrigin>,
56535653+ /// The location of the label, captured before the argument's value is
56545654+ /// discarded: the synthetic replacement value spans the whole argument,
56555655+ /// so it can no longer tell the label and the value apart.
56565656+ label_location: Option<SrcSpan>,
56575657+ /// The syntax of the label, captured before the argument's value is
56585658+ /// discarded for the same reason as `label_location`.
56595659+ syntax: LabelSyntax,
56265660}
5627566156285662/// Given a constants, this will change its type into the given one, turning
···60566090 arguments: Vec<Arc<Type>>,
60576091 return_type: Arc<Type>,
60586092 field_map: &'a FieldMap,
60596059- constructor_name: EcoString,
60606093}
6061609460626095impl RecordUpdateVariant<'_> {
···1212 ast::{self, SrcSpan},
1313 build::Module,
1414 line_numbers::LineNumbers,
1515- reference::{ModuleNameReference, RecordLabel, ReferenceKind},
1515+ reference::{LabelSyntax, ModuleNameReference, RecordLabel, ReferenceKind},
1616 type_::{ModuleInterface, error::Named},
1717};
1818···247247/// label shorthand syntax (`wibble:`), which is expanded so the implicit value
248248/// variable keeps its original name.
249249///
250250-/// All the reference locations come from the reference graph that is built
251251-/// during analysis, exactly like the value and type renaming above.
252252-///
253250pub fn rename_label(
254251 params: &RenameParams,
255252 type_module: &EcoString,
···275272 label: label.clone(),
276273 };
277274275275+ // A label can be referenced in a module that doesn't import the type's
276276+ // defining module: a record value can be obtained transitively through
277277+ // another module and have its fields accessed. So every module has to be
278278+ // searched.
278279 for module in modules.values() {
279279- if &module.name == type_module || module.references.imported_modules.contains(type_module) {
280280- let Some(source_information) = sources.get(&module.name) else {
281281- continue;
282282- };
280280+ let Some(source_information) = sources.get(&module.name) else {
281281+ continue;
282282+ };
283283284284- rename_label_references_in_module(
285285- module,
286286- source_information,
287287- &mut workspace_edit,
288288- &key,
289289- label,
290290- ¶ms.new_name,
291291- );
292292- }
284284+ rename_label_references_in_module(
285285+ module,
286286+ source_information,
287287+ &mut workspace_edit,
288288+ &key,
289289+ label,
290290+ ¶ms.new_name,
291291+ );
293292 }
294293295294 RenameOutcome::Renamed {
···305304 label: &EcoString,
306305 new_name: &str,
307306) {
308308- let Some(references) = module.references.label_references.get(key) else {
307307+ let definitions = module.references.label_definitions.get(key);
308308+ let references = module.references.label_references.get(key);
309309+ if definitions.is_none() && references.is_none() {
309310 return;
310310- };
311311+ }
311312312313 let mut edits = TextEdits::new(&source_information.line_numbers);
313314314314- for reference in references {
315315- if reference.shorthand {
315315+ // The definitions of the field are renamed along with its references. A
316316+ // field shared between multiple variants has a definition in each, and
317317+ // they are all renamed together so that code accessing the shared field
318318+ // keeps compiling.
319319+ for definition in definitions.into_iter().flatten() {
320320+ edits.replace(definition.location, new_name.to_string());
321321+ }
322322+323323+ for reference in references.into_iter().flatten() {
324324+ match reference.syntax {
316325 // A label written using shorthand syntax (`wibble:`) relies on the
317326 // field and the variable sharing a name. Renaming the field alone
318327 // would break that, so we expand the shorthand and keep the original
319328 // name as the value: `wibble:` becomes `new_name: wibble`.
320320- edits.replace(reference.location, format!("{new_name}: {label}"));
321321- } else {
322322- edits.replace(reference.location, new_name.to_string());
329329+ LabelSyntax::Shorthand => {
330330+ edits.replace(reference.location, format!("{new_name}: {label}"))
331331+ }
332332+ LabelSyntax::Longhand => edits.replace(reference.location, new_name.to_string()),
323333 }
324334 }
325335
···12351235 );
12361236}
1237123712381238-// A field elided by a `..` pattern spread is not a reference to that field, so
12391239-// it must not show up in the results.
12381238+#[test]
12391239+fn references_for_record_field_in_module_not_importing_the_type_module() {
12401240+ assert_references!(
12411241+ TestProject::for_source(
12421242+ "
12431243+import wobble
12441244+12451245+pub fn main() {
12461246+ wobble.make().wibble
12471247+}
12481248+"
12491249+ )
12501250+ .add_module("wibble", "pub type Wibble {\n Wibble(wibble: Int)\n}")
12511251+ .add_module(
12521252+ "wobble",
12531253+ "import wibble\n\npub fn make() -> wibble.Wibble {\n wibble.Wibble(wibble: 1)\n}"
12541254+ ),
12551255+ find_position_of("().wibble").under_char('b')
12561256+ );
12571257+}
12581258+12401259#[test]
12411260fn references_for_record_field_ignored_by_pattern_spread() {
12421261 assert_references!(
···29342934}
2935293529362936#[test]
29372937+fn rename_record_field_in_module_not_importing_the_type_module() {
29382938+ assert_rename!(
29392939+ TestProject::for_source(
29402940+ "
29412941+import wobble
29422942+29432943+pub fn main() {
29442944+ wobble.make().wibble
29452945+}
29462946+"
29472947+ )
29482948+ .add_module("wibble", "pub type Wibble {\n Wibble(wibble: Int)\n}")
29492949+ .add_module(
29502950+ "wobble",
29512951+ "import wibble\n\npub fn make() -> wibble.Wibble {\n wibble.Wibble(wibble: 1)\n}"
29522952+ ),
29532953+ "wabble",
29542954+ find_position_of("().wibble").under_char('b')
29552955+ );
29562956+}
29572957+29582958+#[test]
29372959fn rename_record_field_with_invalid_name() {
29382960 assert_rename_error!(
29392961 "
···29692991 );
29702992}
2971299329722972-// A field elided by a `..` pattern spread must not be touched by renaming
29732973-// that field: the spread is not a real label reference, just a synthetic
29742974-// placeholder for the ignored fields.
29942994+#[test]
29952995+fn rename_record_field_renames_labelled_arguments_of_call_with_incorrect_arity() {
29962996+ assert_rename!(
29972997+ "
29982998+type Wibble {
29992999+ Wibble(wibble: Int, wobble: Int)
30003000+}
30013001+30023002+pub fn main() {
30033003+ Wibble(wibble: 1)
30043004+}
30053005+",
30063006+ "wabble",
30073007+ find_position_of("wibble: Int").under_char('w')
30083008+ );
30093009+}
30103010+29753011#[test]
29763012fn rename_record_field_ignored_by_pattern_spread() {
29773013 assert_rename!(
···29913027 );
29923028}
2993302929942994-// A bare `..` eliding every field must likewise be left untouched.
29953030#[test]
29963031fn rename_record_field_ignored_by_bare_pattern_spread() {
29973032 assert_rename!(
···30113046 );
30123047}
3013304830143014-// When multiple variants share a field with the same name, renaming it on one
30153015-// variant renames it on every variant: an accessor like `shape.colour` only
30163016-// works while all the variants share the field, so renaming just one of them
30173017-// would break the others.
30183049#[test]
30193050fn rename_record_field_shared_between_variants() {
30203051 assert_rename!(