Skip to content

Commit b7feb9f

Browse files
committed
introduce the idea of "type must be valid for scope"
Unlike "type must outlive" `T: r`, this relation is between a type and a **program point** `P`. It will eventually be strengthened so that `T valid for P` implies `T: P` but not the reverse (presently, they are equivalent).
1 parent 9e8a982 commit b7feb9f

File tree

2 files changed

+59
-41
lines changed

2 files changed

+59
-41
lines changed

src/librustc_typeck/check/dropck.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -314,16 +314,16 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
314314
// which cannot be outlived.
315315
None => return Ok(()),
316316
};
317-
let parent_scope = rcx.tcx.mk_region(ty::ReScope(parent_scope));
317+
let parent_scope_region = rcx.tcx.mk_region(ty::ReScope(parent_scope));
318318
let origin = || infer::SubregionOrigin::SafeDestructor(span);
319319
let cause = &ObligationCause::misc(span, body_id);
320320
let infer_ok = rcx.infcx.at(cause, rcx.fcx.param_env).dropck_outlives(ty);
321321
debug!("dropck_outlives = {:#?}", infer_ok);
322322
let kinds = rcx.fcx.register_infer_ok_obligations(infer_ok);
323323
for kind in kinds {
324324
match kind.unpack() {
325-
UnpackedKind::Lifetime(r) => rcx.sub_regions(origin(), parent_scope, r),
326-
UnpackedKind::Type(ty) => rcx.type_must_outlive(origin(), ty, parent_scope),
325+
UnpackedKind::Lifetime(r) => rcx.sub_regions(origin(), parent_scope_region, r),
326+
UnpackedKind::Type(ty) => rcx.type_must_be_valid_for_scope(origin(), ty, parent_scope),
327327
}
328328
}
329329
Ok(())

src/librustc_typeck/check/regionck.rs

+56-38
Original file line numberDiff line numberDiff line change
@@ -373,10 +373,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
373373
body.id(),
374374
call_site_scope
375375
);
376-
let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope));
377376

378377
let body_hir_id = self.tcx.hir.node_to_hir_id(body_id.node_id);
379-
self.type_of_node_must_outlive(infer::CallReturn(span), body_hir_id, call_site_region);
378+
self.type_of_node_must_be_valid_for_scope(infer::CallReturn(span), body_hir_id, call_site_scope);
380379

381380
self.constrain_opaque_types(
382381
&self.fcx.opaque_types.borrow(),
@@ -434,10 +433,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
434433
// that the lifetime of any regions that appear in a
435434
// variable's type enclose at least the variable's scope.
436435
let var_scope = self.region_scope_tree.var_scope(hir_id.local_id);
437-
let var_region = self.tcx.mk_region(ty::ReScope(var_scope));
438436

439437
let origin = infer::BindingTypeIsNotValidAtDecl(span);
440-
self.type_of_node_must_outlive(origin, hir_id, var_region);
438+
self.type_of_node_must_be_valid_for_scope(origin, hir_id, var_scope);
441439

442440
let typ = self.resolve_node_type(hir_id);
443441
let body_id = self.body_id;
@@ -520,14 +518,15 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
520518
// scope of that expression. This also guarantees basic WF.
521519
let expr_ty = self.resolve_node_type(expr.hir_id);
522520
// the region corresponding to this expression
523-
let expr_region = self.tcx.mk_region(ty::ReScope(region::Scope {
521+
let expr_scope = region::Scope {
524522
id: expr.hir_id.local_id,
525523
data: region::ScopeData::Node,
526-
}));
527-
self.type_must_outlive(
524+
};
525+
let expr_region = self.tcx.mk_region(ty::ReScope(expr_scope));
526+
self.type_must_be_valid_for_scope(
528527
infer::ExprTypeIsNotInScope(expr_ty, expr.span),
529528
expr_ty,
530-
expr_region,
529+
expr_scope,
531530
);
532531

533532
let is_method_call = self.tables.borrow().is_method_call(expr);
@@ -546,7 +545,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
546545
};
547546

548547
let substs = self.tables.borrow().node_substs(expr.hir_id);
549-
self.substs_wf_in_scope(origin, substs, expr.span, expr_region);
548+
self.substs_wf_in_scope(origin, substs, expr.span, expr_scope);
550549
// Arguments (sub-expressions) are checked via `constrain_call`, below.
551550
}
552551

@@ -572,7 +571,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
572571
hir::ExprKind::Path(_) => {
573572
let substs = self.tables.borrow().node_substs(expr.hir_id);
574573
let origin = infer::ParameterOrigin::Path;
575-
self.substs_wf_in_scope(origin, substs, expr.span, expr_region);
574+
self.substs_wf_in_scope(origin, substs, expr.span, expr_scope);
576575
}
577576

578577
hir::ExprKind::Call(ref callee, ref args) => {
@@ -619,7 +618,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
619618
let lhs_ty = self.resolve_expr_type_adjusted(&lhs);
620619
let rhs_ty = self.resolve_expr_type_adjusted(&rhs);
621620
for &ty in &[lhs_ty, rhs_ty] {
622-
self.type_must_outlive(infer::Operand(expr.span), ty, expr_region);
621+
self.type_must_be_valid_for_scope(infer::Operand(expr.span), ty, expr_scope);
623622
}
624623
intravisit::walk_expr(self, expr);
625624
}
@@ -674,7 +673,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
674673
// FIXME(https://github.com/rust-lang/rfcs/issues/811)
675674
// nested method calls requires that this rule change
676675
let ty0 = self.resolve_node_type(expr.hir_id);
677-
self.type_must_outlive(infer::AddrOf(expr.span), ty0, expr_region);
676+
self.type_must_be_valid_for_scope(infer::AddrOf(expr.span), ty0, expr_scope);
678677
intravisit::walk_expr(self, expr);
679678
}
680679

@@ -705,16 +704,15 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
705704
}
706705

707706
hir::ExprKind::Ret(Some(ref ret_expr)) => {
708-
let call_site_scope = self.call_site_scope;
707+
let call_site_scope = self.call_site_scope.unwrap();
709708
debug!(
710709
"visit_expr ExprKind::Ret ret_expr.id {} call_site_scope: {:?}",
711710
ret_expr.id, call_site_scope
712711
);
713-
let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope.unwrap()));
714-
self.type_of_node_must_outlive(
712+
self.type_of_node_must_be_valid_for_scope(
715713
infer::CallReturn(ret_expr.span),
716714
ret_expr.hir_id,
717-
call_site_region,
715+
call_site_scope,
718716
);
719717
intravisit::walk_expr(self, expr);
720718
}
@@ -813,26 +811,25 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
813811
id: call_expr.hir_id.local_id,
814812
data: region::ScopeData::Node,
815813
};
816-
let callee_region = self.tcx.mk_region(ty::ReScope(callee_scope));
817814

818-
debug!("callee_region={:?}", callee_region);
815+
debug!("callee_scope={:?}", callee_scope);
819816

820817
for arg_expr in arg_exprs {
821818
debug!("Argument: {:?}", arg_expr);
822819

823820
// ensure that any regions appearing in the argument type are
824821
// valid for at least the lifetime of the function:
825-
self.type_of_node_must_outlive(
822+
self.type_of_node_must_be_valid_for_scope(
826823
infer::CallArg(arg_expr.span),
827824
arg_expr.hir_id,
828-
callee_region,
825+
callee_scope,
829826
);
830827
}
831828

832829
// as loop above, but for receiver
833830
if let Some(r) = receiver {
834831
debug!("receiver: {:?}", r);
835-
self.type_of_node_must_outlive(infer::CallRcvr(r.span), r.hir_id, callee_region);
832+
self.type_of_node_must_be_valid_for_scope(infer::CallRcvr(r.span), r.hir_id, callee_scope);
836833
}
837834
}
838835

@@ -867,10 +864,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
867864
// expression.
868865
self.check_safety_of_rvalue_destructor_if_necessary(&cmt, expr.span);
869866

870-
let expr_region = self.tcx.mk_region(ty::ReScope(region::Scope {
867+
let expr_scope = region::Scope {
871868
id: expr.hir_id.local_id,
872869
data: region::ScopeData::Node,
873-
}));
870+
};
871+
let expr_region = self.tcx.mk_region(ty::ReScope(expr_scope));
874872
for adjustment in adjustments {
875873
debug!(
876874
"constrain_adjustments: adjustment={:?}, cmt={:?}",
@@ -905,8 +903,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
905903
);
906904

907905
// Specialized version of constrain_call.
908-
self.type_must_outlive(infer::CallRcvr(expr.span), input, expr_region);
909-
self.type_must_outlive(infer::CallReturn(expr.span), output, expr_region);
906+
self.type_must_be_valid_for_scope(infer::CallRcvr(expr.span), input, expr_scope);
907+
self.type_must_be_valid_for_scope(infer::CallReturn(expr.span), output, expr_scope);
910908
}
911909

912910
if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind {
@@ -916,10 +914,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
916914
// the current node.
917915
//
918916
// FIXME(#6268) remove to support nested method calls
919-
self.type_of_node_must_outlive(
917+
self.type_of_node_must_be_valid_for_scope(
920918
infer::AutoBorrow(expr.span),
921919
expr.hir_id,
922-
expr_region,
920+
expr_scope,
923921
);
924922
}
925923

@@ -999,13 +997,16 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
999997
}
1000998
}
1001999

1002-
/// Guarantees that any lifetimes which appear in the type of the node `id` (after applying
1003-
/// adjustments) are valid for at least `minimum_lifetime`
1004-
fn type_of_node_must_outlive(
1000+
/// Requires that all regions in the (fully adjusted) type of the
1001+
/// node `hir_id` are **valid** during the scope. This means that
1002+
/// they have to outlive `scope`. This implies `T: scope` but is
1003+
/// actually stronger than that in the case of projections. This
1004+
/// helps overcome some weakenesses in our inference (see #55756).
1005+
fn type_of_node_must_be_valid_for_scope(
10051006
&mut self,
10061007
origin: infer::SubregionOrigin<'tcx>,
10071008
hir_id: hir::HirId,
1008-
minimum_lifetime: ty::Region<'tcx>,
1009+
scope: region::Scope,
10091010
) {
10101011
// Try to resolve the type. If we encounter an error, then typeck
10111012
// is going to fail anyway, so just stop here and let typeck
@@ -1021,10 +1022,26 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
10211022
let ty = self.resolve_type(ty);
10221023
debug!(
10231024
"constrain_regions_in_type_of_node(\
1024-
ty={}, ty0={}, id={:?}, minimum_lifetime={:?})",
1025-
ty, ty0, hir_id, minimum_lifetime
1025+
ty={}, ty0={}, id={:?}, scope={:?})",
1026+
ty, ty0, hir_id, scope
10261027
);
1027-
self.type_must_outlive(origin, ty, minimum_lifetime);
1028+
1029+
self.type_must_be_valid_for_scope(origin, ty, scope)
1030+
}
1031+
1032+
/// Requires that all regions in the type `T` are **valid** during
1033+
/// the scope. This means that they have to outlive `scope`. This
1034+
/// implies `T: scope` but is actually stronger than that in the
1035+
/// case of projections. This helps overcome some weakenesses in
1036+
/// our inference (see #55756).
1037+
pub fn type_must_be_valid_for_scope(
1038+
&self,
1039+
origin: infer::SubregionOrigin<'tcx>,
1040+
ty: Ty<'tcx>,
1041+
scope: region::Scope,
1042+
) {
1043+
let region = self.tcx.mk_region(ty::ReScope(scope));
1044+
self.type_must_outlive(origin, ty, region)
10281045
}
10291046

10301047
/// Adds constraints to inference such that `T: 'a` holds (or
@@ -1408,25 +1425,26 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
14081425
origin: infer::ParameterOrigin,
14091426
substs: &Substs<'tcx>,
14101427
expr_span: Span,
1411-
expr_region: ty::Region<'tcx>,
1428+
expr_scope: region::Scope,
14121429
) {
14131430
debug!(
14141431
"substs_wf_in_scope(substs={:?}, \
1415-
expr_region={:?}, \
1432+
expr_scope={:?}, \
14161433
origin={:?}, \
14171434
expr_span={:?})",
1418-
substs, expr_region, origin, expr_span
1435+
substs, expr_scope, origin, expr_span
14191436
);
14201437

14211438
let origin = infer::ParameterInScope(origin, expr_span);
14221439

1440+
let expr_region = self.tcx.mk_region(ty::ReScope(expr_scope));
14231441
for region in substs.regions() {
14241442
self.sub_regions(origin.clone(), expr_region, region);
14251443
}
14261444

14271445
for ty in substs.types() {
14281446
let ty = self.resolve_type(ty);
1429-
self.type_must_outlive(origin.clone(), ty, expr_region);
1447+
self.type_must_be_valid_for_scope(origin.clone(), ty, expr_scope);
14301448
}
14311449
}
14321450
}

0 commit comments

Comments
 (0)