From 6e15faf68a2b1af57d6c94392329d148882d1650 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 10 Feb 2020 19:55:49 +0100 Subject: [PATCH 1/2] Querify object_safety_violations. --- src/librustc/query/mod.rs | 3 + src/librustc/traits/mod.rs | 132 +++++++++++++++ .../infer/error_reporting/mod.rs | 3 +- .../traits/error_reporting/mod.rs | 5 +- .../traits/error_reporting/suggestions.rs | 3 +- src/librustc_infer/traits/mod.rs | 3 +- src/librustc_infer/traits/object_safety.rs | 151 ++---------------- src/librustc_typeck/check/cast.rs | 3 +- src/librustc_typeck/check/coercion.rs | 3 +- src/librustc_typeck/check/wfcheck.rs | 2 +- 10 files changed, 154 insertions(+), 154 deletions(-) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 5e279975d15..df08501f007 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -656,6 +656,9 @@ rustc_queries! { query is_object_safe(key: DefId) -> bool { desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) } } + query object_safety_violations(key: DefId) -> Vec { + desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) } + } /// Gets the ParameterEnvironment for a given item; this environment /// will be in "user-facing" mode, meaning that it is suitabe for diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index c000aa7c25e..de2ec53e51e 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -16,8 +16,10 @@ use crate::ty::{self, AdtKind, List, Ty, TyCtxt}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_span::{Span, DUMMY_SP}; +use smallvec::SmallVec; use syntax::ast; +use std::borrow::Cow; use std::fmt::Debug; use std::rc::Rc; @@ -737,3 +739,133 @@ where tcx: TyCtxt<'tcx>, ) -> Option; } + +#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)] +pub enum ObjectSafetyViolation { + /// `Self: Sized` declared on the trait. + SizedSelf(SmallVec<[Span; 1]>), + + /// Supertrait reference references `Self` an in illegal location + /// (e.g., `trait Foo : Bar`). + SupertraitSelf(SmallVec<[Span; 1]>), + + /// Method has something illegal. + Method(ast::Name, MethodViolationCode, Span), + + /// Associated const. + AssocConst(ast::Name, Span), +} + +impl ObjectSafetyViolation { + pub fn error_msg(&self) -> Cow<'static, str> { + match *self { + ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(), + ObjectSafetyViolation::SupertraitSelf(ref spans) => { + if spans.iter().any(|sp| *sp != DUMMY_SP) { + "it uses `Self` as a type parameter in this".into() + } else { + "it cannot use `Self` as a type parameter in a supertrait or `where`-clause" + .into() + } + } + ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { + format!("associated function `{}` has no `self` parameter", name).into() + } + ObjectSafetyViolation::Method( + name, + MethodViolationCode::ReferencesSelfInput(_), + DUMMY_SP, + ) => format!("method `{}` references the `Self` type in its parameters", name).into(), + ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfInput(_), _) => { + format!("method `{}` references the `Self` type in this parameter", name).into() + } + ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfOutput, _) => { + format!("method `{}` references the `Self` type in its return type", name).into() + } + ObjectSafetyViolation::Method( + name, + MethodViolationCode::WhereClauseReferencesSelf, + _, + ) => { + format!("method `{}` references the `Self` type in its `where` clause", name).into() + } + ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => { + format!("method `{}` has generic type parameters", name).into() + } + ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => { + format!("method `{}`'s `self` parameter cannot be dispatched on", name).into() + } + ObjectSafetyViolation::AssocConst(name, DUMMY_SP) => { + format!("it contains associated `const` `{}`", name).into() + } + ObjectSafetyViolation::AssocConst(..) => "it contains this associated `const`".into(), + } + } + + pub fn solution(&self) -> Option<(String, Option<(String, Span)>)> { + Some(match *self { + ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => { + return None; + } + ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(sugg), _) => ( + format!( + "consider turning `{}` into a method by giving it a `&self` argument or \ + constraining it so it does not apply to trait objects", + name + ), + sugg.map(|(sugg, sp)| (sugg.to_string(), sp)), + ), + ObjectSafetyViolation::Method( + name, + MethodViolationCode::UndispatchableReceiver, + span, + ) => ( + format!("consider changing method `{}`'s `self` parameter to be `&self`", name) + .into(), + Some(("&Self".to_string(), span)), + ), + ObjectSafetyViolation::AssocConst(name, _) + | ObjectSafetyViolation::Method(name, ..) => { + (format!("consider moving `{}` to another trait", name), None) + } + }) + } + + pub fn spans(&self) -> SmallVec<[Span; 1]> { + // When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so + // diagnostics use a `note` instead of a `span_label`. + match self { + ObjectSafetyViolation::SupertraitSelf(spans) + | ObjectSafetyViolation::SizedSelf(spans) => spans.clone(), + ObjectSafetyViolation::AssocConst(_, span) + | ObjectSafetyViolation::Method(_, _, span) + if *span != DUMMY_SP => + { + smallvec![*span] + } + _ => smallvec![], + } + } +} + +/// Reasons a method might not be object-safe. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] +pub enum MethodViolationCode { + /// e.g., `fn foo()` + StaticMethod(Option<(&'static str, Span)>), + + /// e.g., `fn foo(&self, x: Self)` + ReferencesSelfInput(usize), + + /// e.g., `fn foo(&self) -> Self` + ReferencesSelfOutput, + + /// e.g., `fn foo(&self) where Self: Clone` + WhereClauseReferencesSelf, + + /// e.g., `fn foo()` + Generic, + + /// the method's receiver (`self` argument) can't be dispatched on + UndispatchableReceiver, +} diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index 77119b8618f..243feb16237 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -52,7 +52,6 @@ use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePa use crate::infer::opaque_types; use crate::infer::{self, SuppressRegionErrors}; use crate::traits::error_reporting::report_object_safety_error; -use crate::traits::object_safety_violations; use crate::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, }; @@ -1618,7 +1617,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let failure_code = trace.cause.as_failure_code(terr); let mut diag = match failure_code { FailureCode::Error0038(did) => { - let violations = object_safety_violations(self.tcx, did); + let violations = self.tcx.object_safety_violations(did); report_object_safety_error(self.tcx, span, did, violations) } FailureCode::Error0317(failure_str) => { diff --git a/src/librustc_infer/traits/error_reporting/mod.rs b/src/librustc_infer/traits/error_reporting/mod.rs index 4bc8ffc3d2f..2fc7c178977 100644 --- a/src/librustc_infer/traits/error_reporting/mod.rs +++ b/src/librustc_infer/traits/error_reporting/mod.rs @@ -12,7 +12,6 @@ use super::{ use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{self, InferCtxt, TyCtxtInferExt}; -use crate::traits::object_safety_violations; use rustc::mir::interpret::ErrorHandled; use rustc::session::DiagnosticMessageId; use rustc::ty::error::ExpectedFound; @@ -748,7 +747,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } ty::Predicate::ObjectSafe(trait_def_id) => { - let violations = object_safety_violations(self.tcx, trait_def_id); + let violations = self.tcx.object_safety_violations(trait_def_id); report_object_safety_error(self.tcx, span, trait_def_id, violations) } @@ -912,7 +911,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } TraitNotObjectSafe(did) => { - let violations = object_safety_violations(self.tcx, did); + let violations = self.tcx.object_safety_violations(did); report_object_safety_error(self.tcx, span, did, violations) } diff --git a/src/librustc_infer/traits/error_reporting/suggestions.rs b/src/librustc_infer/traits/error_reporting/suggestions.rs index 50ae7c4fbbf..f1206ddf909 100644 --- a/src/librustc_infer/traits/error_reporting/suggestions.rs +++ b/src/librustc_infer/traits/error_reporting/suggestions.rs @@ -5,7 +5,6 @@ use super::{ use crate::infer::InferCtxt; use crate::traits::error_reporting::suggest_constraining_type_param; -use crate::traits::object_safety::object_safety_violations; use rustc::ty::TypeckTables; use rustc::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; @@ -587,7 +586,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // If the `dyn Trait` is not object safe, do not suggest `Box`. predicates .principal_def_id() - .map_or(true, |def_id| object_safety_violations(self.tcx, def_id).is_empty()) + .map_or(true, |def_id| self.tcx.object_safety_violations(def_id).is_empty()) } // We only want to suggest `impl Trait` to `dyn Trait`s. // For example, `fn foo() -> str` needs to be filtered out. diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index 06c6d651813..64bc9f2cb92 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -47,7 +47,6 @@ pub use self::engine::{TraitEngine, TraitEngineExt}; pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; pub use self::object_safety::astconv_object_safety_violations; pub use self::object_safety::is_vtable_safe_method; -pub use self::object_safety::object_safety_violations; pub use self::object_safety::MethodViolationCode; pub use self::object_safety::ObjectSafetyViolation; pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote}; @@ -636,8 +635,8 @@ impl<'tcx> TraitObligation<'tcx> { } pub fn provide(providers: &mut ty::query::Providers<'_>) { + object_safety::provide(providers); *providers = ty::query::Providers { - is_object_safe: object_safety::is_object_safe_provider, specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, diff --git a/src/librustc_infer/traits/object_safety.rs b/src/librustc_infer/traits/object_safety.rs index d36d66e4e25..f409c22831f 100644 --- a/src/librustc_infer/traits/object_safety.rs +++ b/src/librustc_infer/traits/object_safety.rs @@ -19,142 +19,12 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; -use smallvec::{smallvec, SmallVec}; -use syntax::ast; +use rustc_span::Span; +use smallvec::SmallVec; -use std::borrow::Cow; -use std::iter::{self}; +use std::iter; -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum ObjectSafetyViolation { - /// `Self: Sized` declared on the trait. - SizedSelf(SmallVec<[Span; 1]>), - - /// Supertrait reference references `Self` an in illegal location - /// (e.g., `trait Foo : Bar`). - SupertraitSelf(SmallVec<[Span; 1]>), - - /// Method has something illegal. - Method(ast::Name, MethodViolationCode, Span), - - /// Associated const. - AssocConst(ast::Name, Span), -} - -impl ObjectSafetyViolation { - pub fn error_msg(&self) -> Cow<'static, str> { - match *self { - ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(), - ObjectSafetyViolation::SupertraitSelf(ref spans) => { - if spans.iter().any(|sp| *sp != DUMMY_SP) { - "it uses `Self` as a type parameter in this".into() - } else { - "it cannot use `Self` as a type parameter in a supertrait or `where`-clause" - .into() - } - } - ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { - format!("associated function `{}` has no `self` parameter", name).into() - } - ObjectSafetyViolation::Method( - name, - MethodViolationCode::ReferencesSelfInput(_), - DUMMY_SP, - ) => format!("method `{}` references the `Self` type in its parameters", name).into(), - ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfInput(_), _) => { - format!("method `{}` references the `Self` type in this parameter", name).into() - } - ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfOutput, _) => { - format!("method `{}` references the `Self` type in its return type", name).into() - } - ObjectSafetyViolation::Method( - name, - MethodViolationCode::WhereClauseReferencesSelf, - _, - ) => { - format!("method `{}` references the `Self` type in its `where` clause", name).into() - } - ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => { - format!("method `{}` has generic type parameters", name).into() - } - ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => { - format!("method `{}`'s `self` parameter cannot be dispatched on", name).into() - } - ObjectSafetyViolation::AssocConst(name, DUMMY_SP) => { - format!("it contains associated `const` `{}`", name).into() - } - ObjectSafetyViolation::AssocConst(..) => "it contains this associated `const`".into(), - } - } - - pub fn solution(&self) -> Option<(String, Option<(String, Span)>)> { - Some(match *self { - ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => { - return None; - } - ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(sugg), _) => ( - format!( - "consider turning `{}` into a method by giving it a `&self` argument or \ - constraining it so it does not apply to trait objects", - name - ), - sugg.map(|(sugg, sp)| (sugg.to_string(), sp)), - ), - ObjectSafetyViolation::Method( - name, - MethodViolationCode::UndispatchableReceiver, - span, - ) => ( - format!("consider changing method `{}`'s `self` parameter to be `&self`", name) - .into(), - Some(("&Self".to_string(), span)), - ), - ObjectSafetyViolation::AssocConst(name, _) - | ObjectSafetyViolation::Method(name, ..) => { - (format!("consider moving `{}` to another trait", name), None) - } - }) - } - - pub fn spans(&self) -> SmallVec<[Span; 1]> { - // When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so - // diagnostics use a `note` instead of a `span_label`. - match self { - ObjectSafetyViolation::SupertraitSelf(spans) - | ObjectSafetyViolation::SizedSelf(spans) => spans.clone(), - ObjectSafetyViolation::AssocConst(_, span) - | ObjectSafetyViolation::Method(_, _, span) - if *span != DUMMY_SP => - { - smallvec![*span] - } - _ => smallvec![], - } - } -} - -/// Reasons a method might not be object-safe. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum MethodViolationCode { - /// e.g., `fn foo()` - StaticMethod(Option<(&'static str, Span)>), - - /// e.g., `fn foo(&self, x: Self)` - ReferencesSelfInput(usize), - - /// e.g., `fn foo(&self) -> Self` - ReferencesSelfOutput, - - /// e.g., `fn foo(&self) where Self: Clone` - WhereClauseReferencesSelf, - - /// e.g., `fn foo()` - Generic, - - /// the method's receiver (`self` argument) can't be dispatched on - UndispatchableReceiver, -} +pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation}; /// Returns the object safety violations that affect /// astconv -- currently, `Self` in supertraits. This is needed @@ -176,10 +46,7 @@ pub fn astconv_object_safety_violations( violations } -pub fn object_safety_violations( - tcx: TyCtxt<'_>, - trait_def_id: DefId, -) -> Vec { +fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Vec { debug_assert!(tcx.generics_of(trait_def_id).has_self); debug!("object_safety_violations: {:?}", trait_def_id); @@ -905,6 +772,10 @@ fn contains_illegal_self_type_reference<'tcx>( error } -pub(super) fn is_object_safe_provider(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { - object_safety_violations(tcx, trait_def_id).is_empty() +fn is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { + tcx.object_safety_violations(trait_def_id).is_empty() +} + +pub fn provide(providers: &mut ty::query::Providers<'_>) { + *providers = ty::query::Providers { is_object_safe, object_safety_violations, ..*providers }; } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 18f6a78804b..a67ceb856ce 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -45,7 +45,6 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_infer::traits; use rustc_infer::traits::error_reporting::report_object_safety_error; -use rustc_infer::traits::object_safety_violations; use rustc_span::Span; use syntax::ast; @@ -517,7 +516,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) { - let violations = object_safety_violations(fcx.tcx, did); + let violations = fcx.tcx.object_safety_violations(did); let mut err = report_object_safety_error(fcx.tcx, self.cast_span, did, violations); err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty))); err.emit(); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index c327a7996b6..3720b74d92e 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -66,7 +66,6 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, InferOk, InferResult}; -use rustc_infer::traits::object_safety_violations; use rustc_infer::traits::{self, ObligationCause, ObligationCauseCode}; use rustc_span::symbol::sym; use rustc_span::{self, Span}; @@ -1404,7 +1403,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // Are of this `impl Trait`'s traits object safe? is_object_safe = bounds.iter().all(|bound| { bound.trait_def_id().map_or(false, |def_id| { - object_safety_violations(fcx.tcx, def_id).is_empty() + fcx.tcx.object_safety_violations(def_id).is_empty() }) }) } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 4ffc3bf8e78..12e6087dbaf 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -223,7 +223,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem _ => {} } if !trait_should_be_self.is_empty() { - if rustc_infer::traits::object_safety_violations(tcx, trait_def_id).is_empty() { + if tcx.object_safety_violations(trait_def_id).is_empty() { return; } let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect(); From 310f4707e59f696814e0e800be0b5ec6e81353d5 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 19 Feb 2020 17:59:24 +0100 Subject: [PATCH 2/2] Make is_object_safe a method. --- src/librustc/query/mod.rs | 3 --- src/librustc/ty/mod.rs | 4 ++++ src/librustc_incremental/persist/dirty_clean.rs | 2 +- src/librustc_infer/traits/object_safety.rs | 6 +----- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index df08501f007..8c40c28bb47 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -653,9 +653,6 @@ rustc_queries! { desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(key) } cache_on_disk_if { true } } - query is_object_safe(key: DefId) -> bool { - desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) } - } query object_safety_violations(key: DefId) -> Vec { desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 45ea05efd4a..b76c637e3f1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2998,6 +2998,10 @@ impl<'tcx> TyCtxt<'tcx> { }; (ident, scope) } + + pub fn is_object_safe(self, key: DefId) -> bool { + self.object_safety_violations(key).is_empty() + } } #[derive(Clone, HashStable)] diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index c5e74868bda..1fa57f1ecf2 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -78,7 +78,7 @@ const BASE_STRUCT: &[&str] = const BASE_TRAIT_DEF: &[&str] = &[ label_strs::associated_item_def_ids, label_strs::generics_of, - label_strs::is_object_safe, + label_strs::object_safety_violations, label_strs::predicates_of, label_strs::specialization_graph_of, label_strs::trait_def, diff --git a/src/librustc_infer/traits/object_safety.rs b/src/librustc_infer/traits/object_safety.rs index f409c22831f..f2770720346 100644 --- a/src/librustc_infer/traits/object_safety.rs +++ b/src/librustc_infer/traits/object_safety.rs @@ -772,10 +772,6 @@ fn contains_illegal_self_type_reference<'tcx>( error } -fn is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { - tcx.object_safety_violations(trait_def_id).is_empty() -} - pub fn provide(providers: &mut ty::query::Providers<'_>) { - *providers = ty::query::Providers { is_object_safe, object_safety_violations, ..*providers }; + *providers = ty::query::Providers { object_safety_violations, ..*providers }; }