Update handling of Tuple

This commit is contained in:
varkor 2019-04-26 00:27:33 +01:00
parent 283ca7616c
commit a3470c6189
40 changed files with 136 additions and 92 deletions

View file

@ -47,7 +47,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
let field_def = &variant_def.fields[f.index()]; let field_def = &variant_def.fields[f.index()];
field_def.ty(tcx, substs) field_def.ty(tcx, substs)
} }
ty::Tuple(ref tys) => tys[f.index()], ty::Tuple(ref tys) => tys[f.index()].expect_ty(),
_ => bug!("extracting field of non-tuple non-adt: {:?}", self), _ => bug!("extracting field of non-tuple non-adt: {:?}", self),
}; };
debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer); debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer);

View file

@ -875,7 +875,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1); let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
let expected = match expected_ty.sty { let expected = match expected_ty.sty {
ty::Tuple(ref tys) => tys.iter() ty::Tuple(ref tys) => tys.iter()
.map(|t| ArgKind::from_expected_ty(t, Some(span))).collect(), .map(|t| ArgKind::from_expected_ty(t.expect_ty(), Some(span))).collect(),
_ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())], _ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())],
}; };
@ -1247,7 +1247,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let inputs = trait_ref.substs.type_at(1); let inputs = trait_ref.substs.type_at(1);
let sig = if let ty::Tuple(inputs) = inputs.sty { let sig = if let ty::Tuple(inputs) = inputs.sty {
tcx.mk_fn_sig( tcx.mk_fn_sig(
inputs.iter().cloned(), inputs.iter().map(|k| k.expect_ty()),
tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })), tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })),
false, false,
hir::Unsafety::Normal, hir::Unsafety::Normal,

View file

@ -217,7 +217,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) ->
// (T1..Tn) and closures have same properties as T1..Tn -- // (T1..Tn) and closures have same properties as T1..Tn --
// check if *any* of those are trivial. // check if *any* of those are trivial.
ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)), ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())),
ty::Closure(def_id, ref substs) => substs ty::Closure(def_id, ref substs) => substs
.upvar_tys(def_id, tcx) .upvar_tys(def_id, tcx)
.all(|t| trivial_dropck_outlives(tcx, t)), .all(|t| trivial_dropck_outlives(tcx, t)),

View file

@ -2429,7 +2429,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None, ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None,
ty::Tuple(tys) => Where(ty::Binder::bind(tys.last().into_iter().cloned().collect())), ty::Tuple(tys) => {
Where(ty::Binder::bind(tys.last().into_iter().map(|k| k.expect_ty()).collect()))
}
ty::Adt(def, substs) => { ty::Adt(def, substs) => {
let sized_crit = def.sized_constraint(self.tcx()); let sized_crit = def.sized_constraint(self.tcx());
@ -2503,7 +2505,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
ty::Tuple(tys) => { ty::Tuple(tys) => {
// (*) binder moved here // (*) binder moved here
Where(ty::Binder::bind(tys.to_vec())) Where(ty::Binder::bind(tys.iter().map(|k| k.expect_ty()).collect()))
} }
ty::Closure(def_id, substs) => { ty::Closure(def_id, substs) => {
@ -2590,7 +2592,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
ty::Tuple(ref tys) => { ty::Tuple(ref tys) => {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
tys.to_vec() tys.iter().map(|k| k.expect_ty()).collect()
} }
ty::Closure(def_id, ref substs) => substs.upvar_tys(def_id, self.tcx()).collect(), ty::Closure(def_id, ref substs) => substs.upvar_tys(def_id, self.tcx()).collect(),
@ -3495,7 +3497,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// Check that the source tuple with the target's // Check that the source tuple with the target's
// last element is equal to the target. // last element is equal to the target.
let new_tuple = tcx.mk_tup(a_mid.iter().cloned().chain(iter::once(b_last))); let new_tuple = tcx.mk_tup(
a_mid.iter().map(|k| k.expect_ty()).chain(iter::once(b_last.expect_ty())),
);
let InferOk { obligations, .. } = self.infcx let InferOk { obligations, .. } = self.infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.eq(target, new_tuple) .eq(target, new_tuple)
@ -3508,7 +3512,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
obligation.cause.clone(), obligation.cause.clone(),
obligation.predicate.def_id(), obligation.predicate.def_id(),
obligation.recursion_depth + 1, obligation.recursion_depth + 1,
a_last, a_last.expect_ty(),
&[b_last.into()], &[b_last.into()],
)); ));
} }

View file

@ -2431,7 +2431,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
let converted_sig = sig.map_bound(|s| { let converted_sig = sig.map_bound(|s| {
let params_iter = match s.inputs()[0].sty { let params_iter = match s.inputs()[0].sty {
ty::Tuple(params) => { ty::Tuple(params) => {
params.into_iter().cloned() params.into_iter().map(|k| k.expect_ty())
} }
_ => bug!(), _ => bug!(),
}; };
@ -2573,11 +2573,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
#[inline] #[inline]
pub fn intern_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> { pub fn intern_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> {
self.mk_ty(Tuple(self.intern_type_list(ts))) let kinds: Vec<_> = ts.into_iter().map(|&t| Kind::from(t)).collect();
self.mk_ty(Tuple(self.intern_substs(&kinds)))
} }
pub fn mk_tup<I: InternAs<[Ty<'tcx>], Ty<'tcx>>>(self, iter: I) -> I::Output { pub fn mk_tup<I: InternAs<[Ty<'tcx>], Ty<'tcx>>>(self, iter: I) -> I::Output {
iter.intern_with(|ts| self.mk_ty(Tuple(self.intern_type_list(ts)))) iter.intern_with(|ts| {
let kinds: Vec<_> = ts.into_iter().map(|&t| Kind::from(t)).collect();
self.mk_ty(Tuple(self.intern_substs(&kinds)))
})
} }
#[inline] #[inline]

View file

@ -195,8 +195,8 @@ impl FlagComputation {
self.add_ty(ty); self.add_ty(ty);
} }
&ty::Tuple(ref ts) => { &ty::Tuple(ref substs) => {
self.add_tys(&ts[..]); self.add_substs(substs);
} }
&ty::FnDef(_, substs) => { &ty::FnDef(_, substs) => {

View file

@ -181,7 +181,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
Tuple(ref tys) => { Tuple(ref tys) => {
DefIdForest::union(tcx, tys.iter().map(|ty| { DefIdForest::union(tcx, tys.iter().map(|ty| {
ty.uninhabited_from(tcx) ty.expect_ty().uninhabited_from(tcx)
})) }))
} }

View file

@ -626,8 +626,9 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
StructKind::MaybeUnsized StructKind::MaybeUnsized
}; };
univariant(&tys.iter().map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?, univariant(&tys.iter().map(|k| {
&ReprOptions::default(), kind)? self.layout_of(k.expect_ty())
}).collect::<Result<Vec<_>, _>>()?, &ReprOptions::default(), kind)?
} }
// SIMD vector types. // SIMD vector types.
@ -1723,7 +1724,7 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
substs.field_tys(def_id, tcx).nth(i).unwrap() substs.field_tys(def_id, tcx).nth(i).unwrap()
} }
ty::Tuple(tys) => tys[i], ty::Tuple(tys) => tys[i].expect_ty(),
// SIMD vector types. // SIMD vector types.
ty::Adt(def, ..) if def.repr.simd() => { ty::Adt(def, ..) if def.repr.simd() => {

View file

@ -2505,7 +2505,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
Tuple(ref tys) => { Tuple(ref tys) => {
match tys.last() { match tys.last() {
None => vec![], None => vec![],
Some(ty) => self.sized_constraint_for_ty(tcx, ty) Some(ty) => self.sized_constraint_for_ty(tcx, ty.expect_ty()),
} }
} }

View file

@ -264,7 +264,7 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty), ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
ty::Tuple(ref tys) => tys.iter() ty::Tuple(ref tys) => tys.iter()
.filter_map(|ty| characteristic_def_id_of_type(ty)) .filter_map(|ty| characteristic_def_id_of_type(ty.expect_ty()))
.next(), .next(),
ty::FnDef(def_id, _) | ty::FnDef(def_id, _) |

View file

@ -701,7 +701,8 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>:
if let ty::Tuple(ref args) = principal.substs.type_at(0).sty { if let ty::Tuple(ref args) = principal.substs.type_at(0).sty {
let mut projections = predicates.projection_bounds(); let mut projections = predicates.projection_bounds();
if let (Some(proj), None) = (projections.next(), projections.next()) { if let (Some(proj), None) = (projections.next(), projections.next()) {
p!(pretty_fn_sig(args, false, proj.ty)); let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect();
p!(pretty_fn_sig(&tys, false, proj.ty));
resugared = true; resugared = true;
} }
} }

View file

@ -526,7 +526,9 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
(&ty::Tuple(as_), &ty::Tuple(bs)) => (&ty::Tuple(as_), &ty::Tuple(bs)) =>
{ {
if as_.len() == bs.len() { if as_.len() == bs.len() {
Ok(tcx.mk_tup(as_.iter().zip(bs).map(|(a, b)| relation.relate(a, b)))?) Ok(tcx.mk_tup(as_.iter().zip(bs).map(|(a, b)| {
relation.relate(&a.expect_ty(), &b.expect_ty())
}))?)
} else if !(as_.is_empty() || bs.is_empty()) { } else if !(as_.is_empty() || bs.is_empty()) {
Err(TypeError::TupleSize( Err(TypeError::TupleSize(
expected_found(relation, &as_.len(), &bs.len()))) expected_found(relation, &as_.len(), &bs.len())))

View file

@ -1651,7 +1651,9 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
}) })
}) })
} }
ty::Tuple(tys) => tys.iter().any(|ty| ty.conservative_is_privately_uninhabited(tcx)), ty::Tuple(tys) => tys.iter().any(|ty| {
ty.expect_ty().conservative_is_privately_uninhabited(tcx)
}),
ty::Array(ty, len) => { ty::Array(ty, len) => {
match len.assert_usize(tcx) { match len.assert_usize(tcx) {
// If the array is definitely non-empty, it's uninhabited if // If the array is definitely non-empty, it's uninhabited if
@ -2087,8 +2089,9 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) =>
false, false,
ty::Tuple(tys) => ty::Tuple(tys) => {
tys.iter().all(|ty| ty.is_trivially_sized(tcx)), tys.iter().all(|ty| ty.expect_ty().is_trivially_sized(tcx))
}
ty::Adt(def, _substs) => ty::Adt(def, _substs) =>
def.sized_constraint(tcx).is_empty(), def.sized_constraint(tcx).is_empty(),

View file

@ -278,7 +278,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
ty::Tuple(tys) => { ty::Tuple(tys) => {
if let Some((&last_ty, _)) = tys.split_last() { if let Some((&last_ty, _)) = tys.split_last() {
ty = last_ty; ty = last_ty.expect_ty();
} else { } else {
break; break;
} }
@ -316,8 +316,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
(&Tuple(a_tys), &Tuple(b_tys)) (&Tuple(a_tys), &Tuple(b_tys))
if a_tys.len() == b_tys.len() => { if a_tys.len() == b_tys.len() => {
if let Some(a_last) = a_tys.last() { if let Some(a_last) = a_tys.last() {
a = a_last; a = a_last.expect_ty();
b = b_tys.last().unwrap(); b = b_tys.last().unwrap().expect_ty();
} else { } else {
break; break;
} }
@ -795,7 +795,13 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
Tuple(ref ts) => { Tuple(ref ts) => {
// Find non representable // Find non representable
fold_repr(ts.iter().map(|ty| { fold_repr(ts.iter().map(|ty| {
is_type_structurally_recursive(tcx, sp, seen, representable_cache, ty) is_type_structurally_recursive(
tcx,
sp,
seen,
representable_cache,
ty.expect_ty(),
)
})) }))
} }
// Fixed-length vectors. // Fixed-length vectors.
@ -1048,7 +1054,7 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// state transformation pass // state transformation pass
ty::Generator(..) => true, ty::Generator(..) => true,
ty::Tuple(ref tys) => tys.iter().cloned().any(needs_drop), ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).any(needs_drop),
// unions don't have destructors because of the child types, // unions don't have destructors because of the child types,
// only if they manually implement `Drop` (handled above). // only if they manually implement `Drop` (handled above).

View file

@ -120,7 +120,7 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
stack.extend(ts.skip_binder().iter().cloned().rev()); stack.extend(ts.skip_binder().iter().cloned().rev());
} }
ty::Tuple(ts) => { ty::Tuple(ts) => {
stack.extend(ts.iter().cloned().rev()); stack.extend(ts.iter().map(|k| k.expect_ty()).rev());
} }
ty::FnDef(_, substs) => { ty::FnDef(_, substs) => {
stack.extend(substs.types().rev()); stack.extend(substs.types().rev());

View file

@ -265,7 +265,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
ty::Tuple(ref tys) => { ty::Tuple(ref tys) => {
if let Some((_last, rest)) = tys.split_last() { if let Some((_last, rest)) = tys.split_last() {
for elem in rest { for elem in rest {
self.require_sized(elem, traits::TupleElem); self.require_sized(elem.expect_ty(), traits::TupleElem);
} }
} }
} }

View file

@ -426,9 +426,9 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
assert!(!sig.c_variadic && extra_args.is_empty()); assert!(!sig.c_variadic && extra_args.is_empty());
match sig.inputs().last().unwrap().sty { match sig.inputs().last().unwrap().sty {
ty::Tuple(ref tupled_arguments) => { ty::Tuple(tupled_arguments) => {
inputs = &sig.inputs()[0..sig.inputs().len() - 1]; inputs = &sig.inputs()[0..sig.inputs().len() - 1];
tupled_arguments tupled_arguments.iter().map(|k| k.expect_ty()).collect()
} }
_ => { _ => {
bug!("argument to function with \"rust-call\" ABI \ bug!("argument to function with \"rust-call\" ABI \
@ -437,7 +437,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
} }
} else { } else {
assert!(sig.c_variadic || extra_args.is_empty()); assert!(sig.c_variadic || extra_args.is_empty());
extra_args extra_args.to_vec()
}; };
let target = &cx.sess().target.target; let target = &cx.sess().target.target;
@ -587,7 +587,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
let mut fn_ty = FnType { let mut fn_ty = FnType {
ret: arg_of(sig.output(), None), ret: arg_of(sig.output(), None),
args: inputs.iter().chain(extra_args).enumerate().map(|(i, ty)| { args: inputs.iter().cloned().chain(extra_args).enumerate().map(|(i, ty)| {
arg_of(ty, Some(i)) arg_of(ty, Some(i))
}).collect(), }).collect(),
c_variadic: sig.c_variadic, c_variadic: sig.c_variadic,

View file

@ -722,9 +722,10 @@ pub fn type_metadata(
} }
}, },
ty::Tuple(ref elements) => { ty::Tuple(ref elements) => {
let tys: Vec<_> = elements.iter().map(|k| k.expect_ty()).collect();
prepare_tuple_metadata(cx, prepare_tuple_metadata(cx,
t, t,
&elements[..], &tys,
unique_type_id, unique_type_id,
usage_site_span).finalize(cx) usage_site_span).finalize(cx)
} }

View file

@ -392,7 +392,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
if let ty::Tuple(args) = sig.inputs()[sig.inputs().len() - 1].sty { if let ty::Tuple(args) = sig.inputs()[sig.inputs().len() - 1].sty {
signature.extend( signature.extend(
args.iter().map(|argument_type| { args.iter().map(|argument_type| {
Some(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP)) Some(type_metadata(cx, argument_type.expect_ty(), syntax_pos::DUMMY_SP))
}) })
); );
} }

View file

@ -46,7 +46,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty::Tuple(component_types) => { ty::Tuple(component_types) => {
output.push('('); output.push('(');
for &component_type in component_types { for &component_type in component_types {
push_debuginfo_type_name(tcx, component_type, true, output, visited); push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited);
output.push_str(", "); output.push_str(", ");
} }
if !component_types.is_empty() { if !component_types.is_empty() {

View file

@ -2214,7 +2214,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// Closure arguments are wrapped in a tuple, so we need to get the first // Closure arguments are wrapped in a tuple, so we need to get the first
// from that. // from that.
if let ty::Tuple(elems) = argument_ty.sty { if let ty::Tuple(elems) = argument_ty.sty {
let argument_ty = elems.first()?; let argument_ty = elems.first()?.expect_ty();
if let ty::Ref(_, _, _) = argument_ty.sty { if let ty::Ref(_, _, _) = argument_ty.sty {
return Some(AnnotatedBorrowFnSignature::Closure { return Some(AnnotatedBorrowFnSignature::Closure {
argument_ty, argument_ty,

View file

@ -515,7 +515,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// just worry about trying to match up the rustc type // just worry about trying to match up the rustc type
// with the HIR types: // with the HIR types:
(ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => { (ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => {
search_stack.extend(elem_tys.iter().cloned().zip(elem_hir_tys)); search_stack.extend(elem_tys.iter().map(|k| k.expect_ty()).zip(elem_hir_tys));
} }
(ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty)) (ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty))

View file

@ -779,7 +779,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
} }
ty::Tuple(tys) => { ty::Tuple(tys) => {
return match tys.get(field.index()) { return match tys.get(field.index()) {
Some(&ty) => Ok(ty), Some(&ty) => Ok(ty.expect_ty()),
None => Err(FieldAccessError::OutOfRange { None => Err(FieldAccessError::OutOfRange {
field_count: tys.len(), field_count: tys.len(),
}), }),

View file

@ -580,7 +580,7 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
tcx.mk_type_list( tcx.mk_type_list(
iter::once(closure_ty) iter::once(closure_ty)
.chain(inputs.iter().cloned()) .chain(inputs.iter().map(|k| k.expect_ty()))
.chain(iter::once(output)), .chain(iter::once(output)),
) )
}, },

View file

@ -1359,7 +1359,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
{ {
debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty); debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty);
match ty.sty { match ty.sty {
ty::Tuple(ref fs) => fs.into_iter().map(|t| *t).collect(), ty::Tuple(ref fs) => fs.into_iter().map(|t| t.expect_ty()).collect(),
ty::Slice(ty) | ty::Array(ty, _) => match *ctor { ty::Slice(ty) | ty::Array(ty, _) => match *ctor {
Slice(length) => (0..length).map(|_| ty).collect(), Slice(length) => (0..length).map(|_| ty).collect(),
ConstantValue(_) => vec![], ConstantValue(_) => vec![],

View file

@ -272,7 +272,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
ty::Tuple(component_types) => { ty::Tuple(component_types) => {
output.push('('); output.push('(');
for &component_type in component_types { for &component_type in component_types {
self.push_type_name(component_type, output, debug); self.push_type_name(component_type.expect_ty(), output, debug);
output.push_str(", "); output.push_str(", ");
} }
if !component_types.is_empty() { if !component_types.is_empty() {

View file

@ -331,7 +331,7 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
substs.upvar_tys(def_id, tcx) substs.upvar_tys(def_id, tcx)
) )
} }
ty::Tuple(tys) => builder.tuple_like_shim(dest, src, tys.iter().cloned()), ty::Tuple(tys) => builder.tuple_like_shim(dest, src, tys.iter().map(|k| k.expect_ty())),
_ => { _ => {
bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty) bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty)
} }

View file

@ -63,7 +63,7 @@ fn may_have_reference<'a, 'gcx, 'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>)
ty::Array(ty, ..) | ty::Slice(ty) => ty::Array(ty, ..) | ty::Slice(ty) =>
may_have_reference(ty, tcx), may_have_reference(ty, tcx),
ty::Tuple(tys) => ty::Tuple(tys) =>
tys.iter().any(|ty| may_have_reference(ty, tcx)), tys.iter().any(|ty| may_have_reference(ty.expect_ty(), tcx)),
ty::Adt(adt, substs) => ty::Adt(adt, substs) =>
adt.variants.iter().any(|v| v.fields.iter().any(|f| adt.variants.iter().any(|v| v.fields.iter().any(|f|
may_have_reference(f.ty(tcx, substs), tcx) may_have_reference(f.ty(tcx, substs), tcx)

View file

@ -575,7 +575,10 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
let tuple_tmp_args = let tuple_tmp_args =
tuple_tys.iter().enumerate().map(|(i, ty)| { tuple_tys.iter().enumerate().map(|(i, ty)| {
// This is e.g., `tuple_tmp.0` in our example above. // This is e.g., `tuple_tmp.0` in our example above.
let tuple_field = Operand::Move(tuple.clone().field(Field::new(i), ty)); let tuple_field = Operand::Move(tuple.clone().field(
Field::new(i),
ty.expect_ty(),
));
// Spill to a local to make e.g., `tmp0`. // Spill to a local to make e.g., `tmp0`.
self.create_temp_if_necessary(tuple_field, callsite, caller_mir) self.create_temp_if_necessary(tuple_field, callsite, caller_mir)

View file

@ -797,7 +797,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
self.open_drop_for_tuple(&tys) self.open_drop_for_tuple(&tys)
} }
ty::Tuple(tys) => { ty::Tuple(tys) => {
self.open_drop_for_tuple(tys) let tys: Vec<_> = tys.iter().map(|k| k.expect_ty()).collect();
self.open_drop_for_tuple(&tys)
} }
ty::Adt(def, substs) => { ty::Adt(def, substs) => {
if def.is_box() { if def.is_box() {

View file

@ -5,7 +5,7 @@ use rustc::traits::{
ProgramClauseCategory, ProgramClauseCategory,
}; };
use rustc::ty; use rustc::ty;
use rustc::ty::subst::{InternalSubsts, Subst}; use rustc::ty::subst::{Kind, InternalSubsts, Subst};
use rustc::hir; use rustc::hir;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use crate::lowering::Lower; use crate::lowering::Lower;
@ -17,7 +17,7 @@ use crate::generic_types;
fn builtin_impl_clause( fn builtin_impl_clause(
tcx: ty::TyCtxt<'_, '_, 'tcx>, tcx: ty::TyCtxt<'_, '_, 'tcx>,
ty: ty::Ty<'tcx>, ty: ty::Ty<'tcx>,
nested: &[ty::Ty<'tcx>], nested: &[Kind<'tcx>],
trait_def_id: DefId trait_def_id: DefId
) -> ProgramClause<'tcx> { ) -> ProgramClause<'tcx> {
ProgramClause { ProgramClause {
@ -32,7 +32,7 @@ fn builtin_impl_clause(
.cloned() .cloned()
.map(|nested_ty| ty::TraitRef { .map(|nested_ty| ty::TraitRef {
def_id: trait_def_id, def_id: trait_def_id,
substs: tcx.mk_substs_trait(nested_ty, &[]), substs: tcx.mk_substs_trait(nested_ty.expect_ty(), &[]),
}) })
.map(|trait_ref| ty::TraitPredicate { trait_ref }) .map(|trait_ref| ty::TraitPredicate { trait_ref })
.map(|pred| GoalKind::DomainGoal(pred.lower())) .map(|pred| GoalKind::DomainGoal(pred.lower()))
@ -124,7 +124,7 @@ crate fn assemble_builtin_sized_impls<'tcx>(
ty: ty::Ty<'tcx>, ty: ty::Ty<'tcx>,
clauses: &mut Vec<Clause<'tcx>> clauses: &mut Vec<Clause<'tcx>>
) { ) {
let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[ty::Ty<'tcx>]| { let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[Kind<'tcx>]| {
let clause = builtin_impl_clause(tcx, ty, nested, sized_def_id); let clause = builtin_impl_clause(tcx, ty, nested, sized_def_id);
// Bind innermost bound vars that may exist in `ty` and `nested`. // Bind innermost bound vars that may exist in `ty` and `nested`.
clauses.push(Clause::ForAll(ty::Binder::bind(clause))); clauses.push(Clause::ForAll(ty::Binder::bind(clause)));
@ -176,7 +176,7 @@ crate fn assemble_builtin_sized_impls<'tcx>(
// `Sized` if the last type is `Sized` (because else we will get a WF error anyway). // `Sized` if the last type is `Sized` (because else we will get a WF error anyway).
&ty::Tuple(type_list) => { &ty::Tuple(type_list) => {
let type_list = generic_types::type_list(tcx, type_list.len()); let type_list = generic_types::type_list(tcx, type_list.len());
push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &**type_list); push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &type_list);
} }
// Struct def // Struct def
@ -185,7 +185,7 @@ crate fn assemble_builtin_sized_impls<'tcx>(
let adt = tcx.mk_ty(ty::Adt(adt_def, substs)); let adt = tcx.mk_ty(ty::Adt(adt_def, substs));
let sized_constraint = adt_def.sized_constraint(tcx) let sized_constraint = adt_def.sized_constraint(tcx)
.iter() .iter()
.map(|ty| ty.subst(tcx, substs)) .map(|ty| Kind::from(ty.subst(tcx, substs)))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
push_builtin_impl(adt, &sized_constraint); push_builtin_impl(adt, &sized_constraint);
} }
@ -228,7 +228,7 @@ crate fn assemble_builtin_copy_clone_impls<'tcx>(
ty: ty::Ty<'tcx>, ty: ty::Ty<'tcx>,
clauses: &mut Vec<Clause<'tcx>> clauses: &mut Vec<Clause<'tcx>>
) { ) {
let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[ty::Ty<'tcx>]| { let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[Kind<'tcx>]| {
let clause = builtin_impl_clause(tcx, ty, nested, trait_def_id); let clause = builtin_impl_clause(tcx, ty, nested, trait_def_id);
// Bind innermost bound vars that may exist in `ty` and `nested`. // Bind innermost bound vars that may exist in `ty` and `nested`.
clauses.push(Clause::ForAll(ty::Binder::bind(clause))); clauses.push(Clause::ForAll(ty::Binder::bind(clause)));
@ -253,7 +253,10 @@ crate fn assemble_builtin_copy_clone_impls<'tcx>(
// These implement `Copy`/`Clone` if their element types do. // These implement `Copy`/`Clone` if their element types do.
&ty::Array(_, length) => { &ty::Array(_, length) => {
let element_ty = generic_types::bound(tcx, 0); let element_ty = generic_types::bound(tcx, 0);
push_builtin_impl(tcx.mk_ty(ty::Array(element_ty, length)), &[element_ty]); push_builtin_impl(
tcx.mk_ty(ty::Array(element_ty, length)),
&[Kind::from(element_ty)],
);
} }
&ty::Tuple(type_list) => { &ty::Tuple(type_list) => {
let type_list = generic_types::type_list(tcx, type_list.len()); let type_list = generic_types::type_list(tcx, type_list.len());
@ -262,7 +265,9 @@ crate fn assemble_builtin_copy_clone_impls<'tcx>(
&ty::Closure(def_id, ..) => { &ty::Closure(def_id, ..) => {
let closure_ty = generic_types::closure(tcx, def_id); let closure_ty = generic_types::closure(tcx, def_id);
let upvar_tys: Vec<_> = match &closure_ty.sty { let upvar_tys: Vec<_> = match &closure_ty.sty {
ty::Closure(_, substs) => substs.upvar_tys(def_id, tcx).collect(), ty::Closure(_, substs) => {
substs.upvar_tys(def_id, tcx).map(|ty| Kind::from(ty)).collect()
},
_ => bug!(), _ => bug!(),
}; };
push_builtin_impl(closure_ty, &upvar_tys); push_builtin_impl(closure_ty, &upvar_tys);

View file

@ -131,7 +131,7 @@ crate fn wf_clause_for_tuple<'tcx>(
let sized_implemented = type_list[0 .. std::cmp::max(arity, 1) - 1].iter() let sized_implemented = type_list[0 .. std::cmp::max(arity, 1) - 1].iter()
.map(|ty| ty::TraitRef { .map(|ty| ty::TraitRef {
def_id: sized_trait, def_id: sized_trait,
substs: tcx.mk_substs_trait(*ty, ty::List::empty()), substs: tcx.mk_substs_trait(ty.expect_ty(), ty::List::empty()),
}) })
.map(|trait_ref| ty::TraitPredicate { trait_ref }) .map(|trait_ref| ty::TraitPredicate { trait_ref })
.map(|predicate| predicate.lower()); .map(|predicate| predicate.lower());

View file

@ -191,7 +191,7 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>(
} }
ty::Tuple(tys) => tys.iter() ty::Tuple(tys) => tys.iter()
.map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty)) .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty.expect_ty()))
.collect(), .collect(),
ty::Closure(def_id, substs) => substs ty::Closure(def_id, substs) => substs

View file

@ -1,7 +1,7 @@
//! Utilities for creating generic types with bound vars in place of parameter values. //! Utilities for creating generic types with bound vars in place of parameter values.
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::InternalSubsts; use rustc::ty::subst::{Kind, SubstsRef, InternalSubsts};
use rustc::hir; use rustc::hir;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc_target::spec::abi; use rustc_target::spec::abi;
@ -44,11 +44,12 @@ crate fn fn_ptr(
tcx.mk_fn_ptr(fn_sig) tcx.mk_fn_ptr(fn_sig)
} }
crate fn type_list(tcx: ty::TyCtxt<'_, '_, 'tcx>, arity: usize) -> &'tcx ty::List<Ty<'tcx>> { crate fn type_list(tcx: ty::TyCtxt<'_, '_, 'tcx>, arity: usize) -> SubstsRef<'tcx> {
tcx.mk_type_list( tcx.mk_substs(
(0..arity).into_iter() (0..arity).into_iter()
.map(|i| ty::BoundVar::from(i)) .map(|i| ty::BoundVar::from(i))
.map(|var| tcx.mk_ty(ty::Bound(ty::INNERMOST, var.into()))) .map(|var| tcx.mk_ty(ty::Bound(ty::INNERMOST, var.into())))
.map(|ty| Kind::from(ty))
) )
} }

View file

@ -9,6 +9,7 @@ use rustc::infer;
use rustc::infer::type_variable::TypeVariableOrigin; use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::traits::ObligationCauseCode; use rustc::traits::ObligationCauseCode;
use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::{self, Ty, TypeFoldable};
use rustc::ty::subst::Kind;
use syntax::ast; use syntax::ast;
use syntax::source_map::Spanned; use syntax::source_map::Spanned;
use syntax::ptr::P; use syntax::ptr::P;
@ -304,11 +305,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
} }
let max_len = cmp::max(expected_len, elements.len()); let max_len = cmp::max(expected_len, elements.len());
let element_tys_iter = (0..max_len).map(|_| self.next_ty_var( let element_tys_iter = (0..max_len).map(|_| {
// FIXME: `MiscVariable` for now -- obtaining the span and name information // FIXME: `MiscVariable` for now -- obtaining the span and name information
// from all tuple elements isn't trivial. // from all tuple elements isn't trivial.
TypeVariableOrigin::TypeInference(pat.span))); Kind::from(self.next_ty_var(TypeVariableOrigin::TypeInference(pat.span)))
let element_tys = tcx.mk_type_list(element_tys_iter); });
let element_tys = tcx.mk_substs(element_tys_iter);
let pat_ty = tcx.mk_ty(ty::Tuple(element_tys)); let pat_ty = tcx.mk_ty(ty::Tuple(element_tys));
if let Some(mut err) = self.demand_eqtype_diag(pat.span, expected, pat_ty) { if let Some(mut err) = self.demand_eqtype_diag(pat.span, expected, pat_ty) {
err.emit(); err.emit();
@ -321,7 +323,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
tcx.mk_tup(element_tys_iter) tcx.mk_tup(element_tys_iter)
} else { } else {
for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
self.check_pat_walk(elem, &element_tys[i], def_bm, match_discrim_span); self.check_pat_walk(
elem,
&element_tys[i].expect_ty(),
def_bm,
match_discrim_span,
);
} }
pat_ty pat_ty
} }

View file

@ -107,7 +107,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
} }
ty::Tuple(fields) => match fields.last() { ty::Tuple(fields) => match fields.last() {
None => Some(PointerKind::Thin), None => Some(PointerKind::Thin),
Some(f) => self.pointer_kind(f, span)? Some(f) => self.pointer_kind(f.expect_ty(), span)?
}, },
// Pointers to foreign types are thin, despite being unsized // Pointers to foreign types are thin, despite being unsized

View file

@ -274,8 +274,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
); );
let input_tys = match arg_param_ty.sty { let input_tys = match arg_param_ty.sty {
ty::Tuple(tys) => tys.into_iter(), ty::Tuple(tys) => tys.into_iter().map(|k| k.expect_ty()),
_ => return None _ => return None,
}; };
let ret_param_ty = projection.skip_binder().ty; let ret_param_ty = projection.skip_binder().ty;
@ -286,7 +286,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
); );
let sig = self.tcx.mk_fn_sig( let sig = self.tcx.mk_fn_sig(
input_tys.cloned(), input_tys,
ret_param_ty, ret_param_ty,
false, false,
hir::Unsafety::Normal, hir::Unsafety::Normal,

View file

@ -2859,7 +2859,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
sp: Span, sp: Span,
expr_sp: Span, expr_sp: Span,
fn_inputs: &[Ty<'tcx>], fn_inputs: &[Ty<'tcx>],
mut expected_arg_tys: &[Ty<'tcx>], expected_arg_tys: &[Ty<'tcx>],
args: &'gcx [hir::Expr], args: &'gcx [hir::Expr],
c_variadic: bool, c_variadic: bool,
tuple_arguments: TupleArgumentsFlag, tuple_arguments: TupleArgumentsFlag,
@ -2915,29 +2915,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
err.emit(); err.emit();
}; };
let mut expected_arg_tys = expected_arg_tys.to_vec();
let formal_tys = if tuple_arguments == TupleArguments { let formal_tys = if tuple_arguments == TupleArguments {
let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
match tuple_type.sty { match tuple_type.sty {
ty::Tuple(arg_types) if arg_types.len() != args.len() => { ty::Tuple(arg_types) if arg_types.len() != args.len() => {
param_count_error(arg_types.len(), args.len(), "E0057", false, false); param_count_error(arg_types.len(), args.len(), "E0057", false, false);
expected_arg_tys = &[]; expected_arg_tys = vec![];
self.err_args(args.len()) self.err_args(args.len())
} }
ty::Tuple(arg_types) => { ty::Tuple(arg_types) => {
expected_arg_tys = match expected_arg_tys.get(0) { expected_arg_tys = match expected_arg_tys.get(0) {
Some(&ty) => match ty.sty { Some(&ty) => match ty.sty {
ty::Tuple(ref tys) => &tys, ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
_ => &[] _ => vec![],
}, },
None => &[] None => vec![],
}; };
arg_types.to_vec() arg_types.iter().map(|k| k.expect_ty()).collect()
} }
_ => { _ => {
span_err!(tcx.sess, sp, E0059, span_err!(tcx.sess, sp, E0059,
"cannot use call notation; the first type parameter \ "cannot use call notation; the first type parameter \
for the function trait is neither a tuple nor unit"); for the function trait is neither a tuple nor unit");
expected_arg_tys = &[]; expected_arg_tys = vec![];
self.err_args(args.len()) self.err_args(args.len())
} }
} }
@ -2948,7 +2950,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
fn_inputs.to_vec() fn_inputs.to_vec()
} else { } else {
param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false); param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
expected_arg_tys = &[]; expected_arg_tys = vec![];
self.err_args(supplied_arg_count) self.err_args(supplied_arg_count)
} }
} else { } else {
@ -2962,19 +2964,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}; };
param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit); param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
expected_arg_tys = &[]; expected_arg_tys = vec![];
self.err_args(supplied_arg_count) self.err_args(supplied_arg_count)
}; };
// If there is no expectation, expect formal_tys.
let expected_arg_tys = if !expected_arg_tys.is_empty() {
expected_arg_tys
} else {
&formal_tys
};
debug!("check_argument_types: formal_tys={:?}", debug!("check_argument_types: formal_tys={:?}",
formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()); formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>());
// If there is no expectation, expect formal_tys.
let expected_arg_tys = if !expected_arg_tys.is_empty() {
expected_arg_tys
} else {
formal_tys.clone()
};
// Check the arguments. // Check the arguments.
// We do this in a pretty awful way: first we type-check any arguments // We do this in a pretty awful way: first we type-check any arguments
// that are not closures, then we type-check the closures. This is so // that are not closures, then we type-check the closures. This is so
@ -3560,7 +3563,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
autoderef.finalize(self); autoderef.finalize(self);
self.write_field_index(expr.hir_id, index); self.write_field_index(expr.hir_id, index);
return field_ty; return field_ty.expect_ty();
} }
} }
} }
@ -4630,7 +4633,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| { let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| {
let t = match flds { let t = match flds {
Some(ref fs) if i < fs.len() => { Some(ref fs) if i < fs.len() => {
let ety = fs[i]; let ety = fs[i].expect_ty();
self.check_expr_coercable_to_type(&e, ety); self.check_expr_coercable_to_type(&e, ety);
ety ety
} }

View file

@ -288,7 +288,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
ty::Tuple(subtys) => { ty::Tuple(subtys) => {
for &subty in subtys { for &subty in subtys {
self.add_constraints_from_ty(current, subty, variance); self.add_constraints_from_ty(current, subty.expect_ty(), variance);
} }
} }

View file

@ -1136,7 +1136,7 @@ fn external_generic_args(
Some(did) if cx.tcx.lang_items().fn_trait_kind(did).is_some() => { Some(did) if cx.tcx.lang_items().fn_trait_kind(did).is_some() => {
assert!(ty_sty.is_some()); assert!(ty_sty.is_some());
let inputs = match ty_sty { let inputs = match ty_sty {
Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.clean(cx)).collect(), Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(),
_ => return GenericArgs::AngleBracketed { args, bindings }, _ => return GenericArgs::AngleBracketed { args, bindings },
}; };
let output = None; let output = None;
@ -1181,7 +1181,7 @@ impl<'a, 'tcx> Clean<GenericBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>
for ty_s in trait_ref.input_types().skip(1) { for ty_s in trait_ref.input_types().skip(1) {
if let ty::Tuple(ts) = ty_s.sty { if let ty::Tuple(ts) = ty_s.sty {
for &ty_s in ts { for &ty_s in ts {
if let ty::Ref(ref reg, _, _) = ty_s.sty { if let ty::Ref(ref reg, _, _) = ty_s.expect_ty().sty {
if let &ty::RegionKind::ReLateBound(..) = *reg { if let &ty::RegionKind::ReLateBound(..) = *reg {
debug!(" hit an ReLateBound {:?}", reg); debug!(" hit an ReLateBound {:?}", reg);
if let Some(Lifetime(name)) = reg.clean(cx) { if let Some(Lifetime(name)) = reg.clean(cx) {
@ -3066,7 +3066,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
is_generic: false, is_generic: false,
} }
} }
ty::Tuple(ref t) => Tuple(t.clean(cx)), ty::Tuple(ref t) => {
Tuple(t.iter().map(|t| t.expect_ty()).collect::<Vec<_>>().clean(cx))
}
ty::Projection(ref data) => data.clean(cx), ty::Projection(ref data) => data.clean(cx),