|
6 | 6 | //! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file
|
7 | 7 | //! is also responsible for assigning their semantics to implicit lifetimes in trait objects.
|
8 | 8 |
|
| 9 | +use std::assert_matches::assert_matches; |
9 | 10 | use std::cell::RefCell;
|
10 | 11 | use std::fmt;
|
11 | 12 | use std::ops::ControlFlow;
|
@@ -890,12 +891,26 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
890 | 891 | fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: HirId, _: Span) {
|
891 | 892 | match qpath {
|
892 | 893 | hir::QPath::Resolved(maybe_qself, path) => {
|
| 894 | + // Visit the path before the self type since computing the ambient object lifetime default |
| 895 | + // for the latter requires all lifetime arguments of the trait ref to be already resolved. |
| 896 | + self.visit_path(path, id); |
893 | 897 | if let Some(qself) = maybe_qself {
|
894 |
| - // FIXME: Actually properly determine the OLD for the self ty! |
895 |
| - let scope = Scope::ObjectLifetimeDefault { lifetime: None, s: self.scope }; |
896 |
| - self.with(scope, |this| this.visit_ty_unambig(qself)); |
| 898 | + let container = match path.res { |
| 899 | + Res::Def(DefKind::AssocTy, def_id) => Some(( |
| 900 | + self.tcx.parent(def_id), |
| 901 | + &path.segments[..path.segments.len() - 1], |
| 902 | + )), |
| 903 | + _ => None, |
| 904 | + }; |
| 905 | + let object_lifetime_defaults = |
| 906 | + container.map_or(Vec::new(), |(def_id, segs)| self.xyzxx(def_id, segs)); |
| 907 | + if let Some(<) = object_lifetime_defaults.get(0) { |
| 908 | + let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope }; |
| 909 | + self.with(scope, |this| this.visit_ty_unambig(qself)); |
| 910 | + } else { |
| 911 | + self.visit_ty_unambig(qself); |
| 912 | + } |
897 | 913 | }
|
898 |
| - self.visit_path(path, id); |
899 | 914 | }
|
900 | 915 | hir::QPath::TypeRelative(qself, segment) => {
|
901 | 916 | // Resolving object lifetime defaults for type-relative paths requires type-dependent
|
@@ -1058,51 +1073,57 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
1058 | 1073 | }
|
1059 | 1074 |
|
1060 | 1075 | fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectLifetimeDefault {
|
1061 |
| - let hir::Node::GenericParam(param) = tcx.hir_node_by_def_id(param_def_id) else { |
1062 |
| - bug!("expected GenericParam for object_lifetime_default"); |
| 1076 | + // FIXME: Update comments etc. |
| 1077 | + |
| 1078 | + // Scan the bounds and where-clauses on parameters to extract bounds |
| 1079 | + // of the form `T: 'a` so as to determine the `ObjectLifetimeDefault` |
| 1080 | + // for each type parameter. |
| 1081 | + |
| 1082 | + let (generics, bounds) = match tcx.hir_node_by_def_id(param_def_id) { |
| 1083 | + hir::Node::GenericParam(param) => match param.source { |
| 1084 | + hir::GenericParamSource::Generics => { |
| 1085 | + // FIXME: message |
| 1086 | + assert_matches!(param.kind, GenericParamKind::Type { .. }); |
| 1087 | + (tcx.hir_get_generics(tcx.local_parent(param_def_id)).unwrap(), &[][..]) |
| 1088 | + } |
| 1089 | + hir::GenericParamSource::Binder => return ObjectLifetimeDefault::Empty, |
| 1090 | + }, |
| 1091 | + // For Self ty params |
| 1092 | + hir::Node::Item(&hir::Item { |
| 1093 | + kind: hir::ItemKind::Trait(_, _, _, generics, bounds, _), |
| 1094 | + .. |
| 1095 | + }) => (generics, bounds), |
| 1096 | + _ => bug!("`object_lifetime_default` must only be called on type parameters"), |
1063 | 1097 | };
|
1064 |
| - match param.source { |
1065 |
| - hir::GenericParamSource::Generics => { |
1066 |
| - let parent_def_id = tcx.local_parent(param_def_id); |
1067 |
| - let generics = tcx.hir_get_generics(parent_def_id).unwrap(); |
1068 |
| - |
1069 |
| - // Scan the bounds and where-clauses on parameters to extract bounds |
1070 |
| - // of the form `T:'a` so as to determine the `ObjectLifetimeDefault` |
1071 |
| - // for each type parameter. |
1072 |
| - match param.kind { |
1073 |
| - GenericParamKind::Type { .. } => { |
1074 |
| - let mut set = Set1::Empty; |
1075 |
| - |
1076 |
| - // Look for `type: ...` where clauses. |
1077 |
| - for bound in generics.bounds_for_param(param_def_id) { |
1078 |
| - // Ignore `for<'a> type: ...` as they can change what |
1079 |
| - // lifetimes mean (although we could "just" handle it). |
1080 |
| - if !bound.bound_generic_params.is_empty() { |
1081 |
| - continue; |
1082 |
| - } |
1083 | 1098 |
|
1084 |
| - for bound in bound.bounds { |
1085 |
| - if let hir::GenericBound::Outlives(lifetime) = bound { |
1086 |
| - set.insert(lifetime.kind); |
1087 |
| - } |
1088 |
| - } |
1089 |
| - } |
| 1099 | + let mut set = Set1::Empty; |
1090 | 1100 |
|
1091 |
| - match set { |
1092 |
| - Set1::Empty => ObjectLifetimeDefault::Empty, |
1093 |
| - Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static, |
1094 |
| - Set1::One(hir::LifetimeKind::Param(param_def_id)) => { |
1095 |
| - ObjectLifetimeDefault::Param(param_def_id.to_def_id()) |
1096 |
| - } |
1097 |
| - _ => ObjectLifetimeDefault::Ambiguous, |
1098 |
| - } |
1099 |
| - } |
1100 |
| - _ => { |
1101 |
| - bug!("object_lifetime_default must only be called on a type parameter") |
1102 |
| - } |
| 1101 | + let mut add_outlives_bounds = |bounds: &[hir::GenericBound<'_>]| { |
| 1102 | + for bound in bounds { |
| 1103 | + if let hir::GenericBound::Outlives(lifetime) = bound { |
| 1104 | + set.insert(lifetime.res); |
1103 | 1105 | }
|
1104 | 1106 | }
|
1105 |
| - hir::GenericParamSource::Binder => ObjectLifetimeDefault::Empty, |
| 1107 | + }; |
| 1108 | + |
| 1109 | + add_outlives_bounds(bounds); |
| 1110 | + |
| 1111 | + // Look for `Type: ...` where clauses. |
| 1112 | + for bound in generics.bounds_for_param(param_def_id) { |
| 1113 | + // Ignore `for<'a> Type: ...` as they can change what |
| 1114 | + // lifetimes mean (although we could "just" handle it). |
| 1115 | + if !bound.bound_generic_params.is_empty() { |
| 1116 | + add_outlives_bounds(&bound.bounds); |
| 1117 | + } |
| 1118 | + } |
| 1119 | + |
| 1120 | + match set { |
| 1121 | + Set1::Empty => ObjectLifetimeDefault::Empty, |
| 1122 | + Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static, |
| 1123 | + Set1::One(hir::LifetimeKind::Param(param_def_id)) => { |
| 1124 | + ObjectLifetimeDefault::Param(param_def_id.to_def_id()) |
| 1125 | + } |
| 1126 | + _ => ObjectLifetimeDefault::Ambiguous, |
1106 | 1127 | }
|
1107 | 1128 | }
|
1108 | 1129 |
|
@@ -1683,88 +1704,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
1683 | 1704 | // Therefore, we would compute `object_lifetime_defaults` to a
|
1684 | 1705 | // vector like `['x, 'static]`. Note that the vector only
|
1685 | 1706 | // includes type parameters.
|
1686 |
| - let object_lifetime_defaults = type_def_id.map_or_else(Vec::new, |def_id| { |
1687 |
| - let in_body = { |
1688 |
| - let mut scope = self.scope; |
1689 |
| - loop { |
1690 |
| - match *scope { |
1691 |
| - Scope::Root { .. } => break false, |
1692 |
| - |
1693 |
| - Scope::Body { .. } => break true, |
1694 |
| - |
1695 |
| - Scope::Binder { s, .. } |
1696 |
| - | Scope::ObjectLifetimeDefault { s, .. } |
1697 |
| - | Scope::Opaque { s, .. } |
1698 |
| - | Scope::Supertrait { s, .. } |
1699 |
| - | Scope::TraitRefBoundary { s, .. } |
1700 |
| - | Scope::LateBoundary { s, .. } => { |
1701 |
| - scope = s; |
1702 |
| - } |
1703 |
| - } |
1704 |
| - } |
1705 |
| - }; |
1706 |
| - |
1707 |
| - let rbv = &self.rbv; |
1708 |
| - let generics = self.tcx.generics_of(def_id); |
1709 |
| - |
1710 |
| - let set_to_region = |set: ObjectLifetimeDefault| match set { |
1711 |
| - ObjectLifetimeDefault::Empty => { |
1712 |
| - if in_body { |
1713 |
| - None |
1714 |
| - } else { |
1715 |
| - Some(ResolvedArg::StaticLifetime) |
1716 |
| - } |
1717 |
| - } |
1718 |
| - ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime), |
1719 |
| - ObjectLifetimeDefault::Param(param_def_id) => { |
1720 |
| - fn param_to_depth_and_index( |
1721 |
| - generics: &ty::Generics, |
1722 |
| - tcx: TyCtxt<'_>, |
1723 |
| - def_id: DefId, |
1724 |
| - ) -> (usize, usize) { |
1725 |
| - if let Some(&index) = generics.param_def_id_to_index.get(&def_id) { |
1726 |
| - let has_self = generics.parent.is_none() && generics.has_self; |
1727 |
| - (0, index as usize - generics.parent_count - has_self as usize) |
1728 |
| - } else if let Some(parent) = generics.parent { |
1729 |
| - let parent = tcx.generics_of(parent); |
1730 |
| - let (index, depth) = param_to_depth_and_index(parent, tcx, def_id); |
1731 |
| - (depth + 1, index) |
1732 |
| - } else { |
1733 |
| - unreachable!() |
1734 |
| - } |
1735 |
| - } |
1736 |
| - |
1737 |
| - let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id); |
1738 |
| - path.segments[path.segments.len() - depth - 1] |
1739 |
| - .args |
1740 |
| - .and_then(|args| args.args.get(index)) |
1741 |
| - .and_then(|arg| match arg { |
1742 |
| - GenericArg::Lifetime(lt) => rbv.defs.get(<.hir_id.local_id).copied(), |
1743 |
| - _ => None, |
1744 |
| - }) |
1745 |
| - } |
1746 |
| - ObjectLifetimeDefault::Ambiguous => None, |
1747 |
| - }; |
1748 |
| - generics |
1749 |
| - .own_params |
1750 |
| - .iter() |
1751 |
| - .filter_map(|param| { |
1752 |
| - match self.tcx.def_kind(param.def_id) { |
1753 |
| - // Generic consts don't impose any constraints. |
1754 |
| - // |
1755 |
| - // We still store a dummy value here to allow generic parameters |
1756 |
| - // in an arbitrary order. |
1757 |
| - DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty), |
1758 |
| - DefKind::TyParam => Some(self.tcx.object_lifetime_default(param.def_id)), |
1759 |
| - // We may also get a `Trait` or `TraitAlias` because of how generics `Self` parameter |
1760 |
| - // works. Ignore it because it can't have a meaningful lifetime default. |
1761 |
| - DefKind::LifetimeParam | DefKind::Trait | DefKind::TraitAlias => None, |
1762 |
| - dk => bug!("unexpected def_kind {:?}", dk), |
1763 |
| - } |
1764 |
| - }) |
1765 |
| - .map(set_to_region) |
1766 |
| - .collect() |
1767 |
| - }); |
| 1707 | + let object_lifetime_defaults = |
| 1708 | + type_def_id.map_or_else(Vec::new, |def_id| self.xyzxx(def_id, &path.segments)); |
1768 | 1709 |
|
1769 | 1710 | debug!(?object_lifetime_defaults);
|
1770 | 1711 |
|
@@ -1899,6 +1840,88 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
1899 | 1840 | }
|
1900 | 1841 | }
|
1901 | 1842 |
|
| 1843 | + fn xyzxx(&self, def_id: DefId, segments: &[hir::PathSegment<'_>]) -> Vec<Option<ResolvedArg>> { |
| 1844 | + let in_body = { |
| 1845 | + let mut scope = self.scope; |
| 1846 | + loop { |
| 1847 | + match *scope { |
| 1848 | + Scope::Root { .. } => break false, |
| 1849 | + |
| 1850 | + Scope::Body { .. } => break true, |
| 1851 | + |
| 1852 | + Scope::Binder { s, .. } |
| 1853 | + | Scope::ObjectLifetimeDefault { s, .. } |
| 1854 | + | Scope::Opaque { s, .. } |
| 1855 | + | Scope::Supertrait { s, .. } |
| 1856 | + | Scope::TraitRefBoundary { s, .. } |
| 1857 | + | Scope::LateBoundary { s, .. } => { |
| 1858 | + scope = s; |
| 1859 | + } |
| 1860 | + } |
| 1861 | + } |
| 1862 | + }; |
| 1863 | + |
| 1864 | + let generics = self.tcx.generics_of(def_id); |
| 1865 | + |
| 1866 | + let set_to_region = |set: ObjectLifetimeDefault| match set { |
| 1867 | + ObjectLifetimeDefault::Empty => { |
| 1868 | + if in_body { |
| 1869 | + None |
| 1870 | + } else { |
| 1871 | + Some(ResolvedArg::StaticLifetime) |
| 1872 | + } |
| 1873 | + } |
| 1874 | + ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime), |
| 1875 | + ObjectLifetimeDefault::Param(param_def_id) => { |
| 1876 | + fn param_to_depth_and_index( |
| 1877 | + generics: &ty::Generics, |
| 1878 | + tcx: TyCtxt<'_>, |
| 1879 | + def_id: DefId, |
| 1880 | + ) -> (usize, usize) { |
| 1881 | + if let Some(&index) = generics.param_def_id_to_index.get(&def_id) { |
| 1882 | + let has_self = generics.parent.is_none() && generics.has_self; |
| 1883 | + (0, index as usize - generics.parent_count - has_self as usize) |
| 1884 | + } else if let Some(parent) = generics.parent { |
| 1885 | + let parent = tcx.generics_of(parent); |
| 1886 | + let (index, depth) = param_to_depth_and_index(parent, tcx, def_id); |
| 1887 | + (depth + 1, index) |
| 1888 | + } else { |
| 1889 | + unreachable!() |
| 1890 | + } |
| 1891 | + } |
| 1892 | + |
| 1893 | + let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id); |
| 1894 | + segments[segments.len() - depth - 1] |
| 1895 | + .args |
| 1896 | + .and_then(|args| args.args.get(index)) |
| 1897 | + .and_then(|arg| match arg { |
| 1898 | + GenericArg::Lifetime(lt) => self.rbv.defs.get(<.hir_id.local_id).copied(), |
| 1899 | + _ => None, |
| 1900 | + }) |
| 1901 | + } |
| 1902 | + ObjectLifetimeDefault::Ambiguous => None, |
| 1903 | + }; |
| 1904 | + generics |
| 1905 | + .own_params |
| 1906 | + .iter() |
| 1907 | + .filter_map(|param| { |
| 1908 | + match self.tcx.def_kind(param.def_id) { |
| 1909 | + // Generic consts don't impose any constraints. |
| 1910 | + // |
| 1911 | + // We still store a dummy value here to allow generic parameters |
| 1912 | + // in an arbitrary order. |
| 1913 | + DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty), |
| 1914 | + DefKind::TyParam | DefKind::Trait => { |
| 1915 | + Some(self.tcx.object_lifetime_default(param.def_id)) |
| 1916 | + } |
| 1917 | + DefKind::LifetimeParam | DefKind::TraitAlias => None, |
| 1918 | + dk => bug!("unexpected def_kind {:?}", dk), |
| 1919 | + } |
| 1920 | + }) |
| 1921 | + .map(set_to_region) |
| 1922 | + .collect() |
| 1923 | + } |
| 1924 | + |
1902 | 1925 | /// Returns all the late-bound vars that come into scope from supertrait HRTBs, based on the
|
1903 | 1926 | /// associated type name and starting trait.
|
1904 | 1927 | /// For example, imagine we have
|
|
0 commit comments