compiler: Track region loan expiry with checked source identities

9c9a3c129965e4881736d64b3ee30d2f2800244258350f630a3ba3bc8c293085
Alexis Sellier committed ago 1 parent 186b07ed
lib/std/lang/resolver.rad +34 -15
991 991
        return MatchSubject { effectiveTy: *target, by };
992 992
    }
993 993
    return MatchSubject { effectiveTy: ty, by: MatchBy::Value };
994 994
}
995 995
996 +
/// Source nodes that define the identities in one region environment.
997 +
export union RegionDeclarations: Copy {
998 +
    /// Declaration parameters, including any non-region constraints.
999 +
    Parameters(*[*ast::Node]),
1000 +
    /// Single region introduced by a lexical block.
1001 +
    Block(*ast::Node),
1002 +
}
1003 +
996 1004
/// Region names introduced by a declaration or lexical block.
997 1005
export record RegionScope: Copy {
1006 +
    /// Immutable source declarations that supply region identities.
1007 +
    declarations: RegionDeclarations,
998 1008
    /// Entries in declaration order.
999 1009
    entries: *unsafe [*unsafe mut types::Region],
1000 1010
    /// Enclosing lexical region environment.
1001 1011
    parent: ?*RegionScope,
1002 1012
}
1139 1149
        set *region = types::Region { id: node.id, origin: types::RegionOrigin::Parameter, name, parent: nil };
1140 1150
        set entries[index] = region;
1141 1151
        set index += 1;
1142 1152
    }
1143 1153
    let scope = try! alloc::alloc(&mut *self.arena, @sizeOf(RegionScope), @alignOf(RegionScope)) as *mut RegionScope;
1144 -
    set *scope = RegionScope { entries, parent: nil };
1154 +
    set *scope = RegionScope { declarations: RegionDeclarations::Parameters(nodes), entries, parent: nil };
1145 1155
    let frozen: *RegionScope = scope;
1146 1156
    set index = 0;
1147 1157
    for node in nodes {
1148 1158
        let case ast::NodeValue::Region { parent, .. } = node.value else continue;
1149 1159
        if let parentNode = parent {
2738 2748
    scope: ?*RegionScope, dependency: *unsafe types::Region, destination: ?*unsafe types::Region
2739 2749
) -> bool {
2740 2750
    if let region = destination {
2741 2751
        return types::regionContains(dependency, region);
2742 2752
    }
2743 -
    return regionInScope(scope, dependency);
2753 +
    return regionInScope(scope, dependency.id);
2744 2754
}
2745 2755
2746 2756
/// Require stored references to cover the lifetime of checked destination storage.
2747 2757
unsafe fn validateRegionalStore 'arena (self: &mut Resolver 'arena, place: *ast::Node, value: *ast::Node, ty: Type)
2748 2758
    throws (ResolveError)
3987 3997
    let entries = try! alloc::allocRawSlice(
3988 3998
        self.arena, @sizeOf(*unsafe mut types::Region), @alignOf(*unsafe mut types::Region), 1
3989 3999
    ) as *unsafe mut [*unsafe mut types::Region];
3990 4000
    set entries[0] = region;
3991 4001
    let scope = try! alloc::alloc(&mut *self.arena, @sizeOf(RegionScope), @alignOf(RegionScope)) as *mut RegionScope;
3992 -
    set *scope = RegionScope { entries, parent: self.regionScope };
4002 +
    set *scope = RegionScope { declarations: RegionDeclarations::Block(node), entries, parent: self.regionScope };
3993 4003
    return scope;
3994 4004
}
3995 4005
3996 4006
/// Qualify an existing-place borrow with its block's region.
3997 4007
unsafe fn qualifyBlockBorrow 'arena (
10061 10071
10062 10072
/// A projection loan that remains active until its named region ends.
10063 10073
record RegionalLoan: Copy {
10064 10074
    /// Address expression that supplies access to the loan.
10065 10075
    source: *ast::Node,
10066 -
    /// Declared lifetime of the projection.
10067 -
    region: *unsafe types::Region,
10076 +
    /// Source identity of the projection's declared lifetime.
10077 +
    regionId: u32,
10068 10078
    /// Storage protected by the projection.
10069 10079
    place: BorrowPlace,
10070 10080
    /// Whether accesses through other references are excluded.
10071 10081
    exclusive: bool,
10072 10082
}
10073 10083
10074 10084
/// Return whether a region identity is visible in a lexical environment.
10075 -
unsafe fn regionInScope(scope: ?*RegionScope, region: *unsafe types::Region) -> bool {
10085 +
fn regionInScope(scope: ?*RegionScope, regionId: u32) -> bool {
10076 10086
    let mut cursor = scope;
10077 10087
    while let current = cursor {
10078 -
        for entry in current.entries {
10079 -
            if entry.id == region.id {
10080 -
                return true;
10088 +
        match current.declarations {
10089 +
            case RegionDeclarations::Parameters(nodes) => {
10090 +
                for node in nodes {
10091 +
                    if let case ast::NodeValue::Region { .. } = node.value; node.id == regionId {
10092 +
                        return true;
10093 +
                    }
10094 +
                }
10095 +
            }
10096 +
            case RegionDeclarations::Block(node) => {
10097 +
                if node.id == regionId {
10098 +
                    return true;
10099 +
                }
10081 10100
            }
10082 10101
        }
10083 10102
        set cursor = current.parent;
10084 10103
    }
10085 10104
    return false;
10086 10105
}
10087 10106
10088 10107
/// Retain only loans whose regions remain active at a control-flow destination.
10089 -
unsafe fn regionalLoansInScope 'arena 'checking (checker: &LinearChecker 'arena 'checking, mask: u64, scope: ?*RegionScope) -> u64 where 'arena: 'checking {
10108 +
fn regionalLoansInScope 'arena 'checking (checker: &LinearChecker 'arena 'checking, mask: u64, scope: ?*RegionScope) -> u64 where 'arena: 'checking {
10090 10109
    let mut result: u64 = 0;
10091 10110
    for i in 0..checker.regionalLen {
10092 10111
        let bit = (1 as u64) << (i as u64);
10093 -
        if (mask & bit) <> 0 and regionInScope(scope, checker.regional[i].region) {
10112 +
        if (mask & bit) <> 0 and regionInScope(scope, checker.regional[i].regionId) {
10094 10113
            set result |= bit;
10095 10114
        }
10096 10115
    }
10097 10116
    return result;
10098 10117
}
10107 10126
    }
10108 10127
    return result;
10109 10128
}
10110 10129
10111 10130
/// Reclaim ended-region entries and preserve loans for enclosing regions.
10112 -
unsafe fn compactRegionalLoans 'arena 'checking (
10131 +
fn compactRegionalLoans 'arena 'checking (
10113 10132
    checker: &mut LinearChecker 'arena 'checking, env: &mut LinearEnv,
10114 10133
    scope: ?*RegionScope
10115 10134
) where 'arena: 'checking {
10116 10135
    let oldLen = checker.regionalLen;
10117 10136
    let mut mapping: [u64; MAX_REGIONAL_LOANS] = [0; MAX_REGIONAL_LOANS];
10118 10137
    let mut next: u32 = 0;
10119 10138
    for i in 0..oldLen {
10120 10139
        let loan = checker.regional[i];
10121 -
        if regionInScope(scope, loan.region) {
10140 +
        if regionInScope(scope, loan.regionId) {
10122 10141
            set checker.regional[next] = loan;
10123 10142
            set mapping[i] = (1 as u64) << (next as u64);
10124 10143
            set next += 1;
10125 10144
        }
10126 10145
    }
10172 10191
    }
10173 10192
    if checker.regionalLen >= MAX_REGIONAL_LOANS {
10174 10193
        throw emitError(checker.resolver, node, ErrorKind::RegionalLoanOverflow);
10175 10194
    }
10176 10195
    let index = checker.regionalLen;
10177 -
    set checker.regional[index] = RegionalLoan { source: node, region, place, exclusive: ast::isExclusiveAddress(address) };
10196 +
    set checker.regional[index] = RegionalLoan { source: node, regionId: region.id, place, exclusive: ast::isExclusiveAddress(address) };
10178 10197
    set checker.regionalLen += 1;
10179 10198
    set env.regionalLoans |= (1 as u64) << (index as u64);
10180 10199
}
10181 10200
10182 10201
/// Return whether an initializer copies a shared reference with a named region.
10525 10544
        }
10526 10545
    }
10527 10546
}
10528 10547
10529 10548
/// Record the ownership state of a loop's condition-false exit.
10530 -
unsafe fn setLinearLoopNaturalExit 'arena 'checking (checker: &mut LinearChecker 'arena 'checking, env: &LinearEnv) where 'arena: 'checking {
10549 +
fn setLinearLoopNaturalExit 'arena 'checking (checker: &mut LinearChecker 'arena 'checking, env: &LinearEnv) where 'arena: 'checking {
10531 10550
    assert checker.loopDepth > 0, "linear loop exit outside loop";
10532 10551
    let depth = checker.loopDepth - 1;
10533 10552
    set checker.loopExitLoans[depth] |= regionalLoansInScope(checker, env.regionalLoans, checker.loopRegions[depth]);
10534 10553
    set checker.loopExitAvailable[depth] = env.available;
10535 10554
    set checker.loopHasNaturalExit[depth] = true;