fix: copy path to store in concatStringsWithContext
This commit is contained in:
@@ -84,23 +84,20 @@ export const withContext = <T>(message: string, span: string, fn: () => T): T =>
|
|||||||
* - Path mode: Store contexts are forbidden (will throw error)
|
* - Path mode: Store contexts are forbidden (will throw error)
|
||||||
* - String mode: All contexts are preserved and merged
|
* - String mode: All contexts are preserved and merged
|
||||||
*
|
*
|
||||||
* If first element is a path, result is a path (with constraint: no store context allowed)
|
|
||||||
*
|
|
||||||
* @param parts - Array of values to concatenate
|
* @param parts - Array of values to concatenate
|
||||||
|
* @param forceString - If true, result is always a string (paths are copied to store)
|
||||||
* @returns String or Path with merged contexts from all parts
|
* @returns String or Path with merged contexts from all parts
|
||||||
*/
|
*/
|
||||||
export const concatStringsWithContext = (parts: NixValue[]): NixString | NixPath => {
|
export const concatStringsWithContext = (parts: NixValue[], forceString: boolean): NixString | NixPath => {
|
||||||
if (parts.length === 0) {
|
if (parts.length === 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const forced = parts.map(force);
|
const forced = parts.map(force);
|
||||||
|
|
||||||
// Check if first element is a path
|
const firstIsPath = !forceString && isNixPath(forced[0]);
|
||||||
const firstIsPath = isNixPath(forced[0]);
|
|
||||||
|
|
||||||
if (firstIsPath) {
|
if (firstIsPath) {
|
||||||
// Path concatenation mode: result will be a path
|
|
||||||
let result = (forced[0] as NixPath).value;
|
let result = (forced[0] as NixPath).value;
|
||||||
|
|
||||||
for (let i = 1; i < forced.length; i++) {
|
for (let i = 1; i < forced.length; i++) {
|
||||||
@@ -111,13 +108,11 @@ export const concatStringsWithContext = (parts: NixValue[]): NixString | NixPath
|
|||||||
} else if (typeof part === "string") {
|
} else if (typeof part === "string") {
|
||||||
result += part;
|
result += part;
|
||||||
} else if (isStringWithContext(part)) {
|
} else if (isStringWithContext(part)) {
|
||||||
// Lix constraint: cannot mix store context with paths
|
|
||||||
if (part.context.size > 0) {
|
if (part.context.size > 0) {
|
||||||
throw new TypeError("a string that refers to a store path cannot be appended to a path");
|
throw new TypeError("a string that refers to a store path cannot be appended to a path");
|
||||||
}
|
}
|
||||||
result += part.value;
|
result += part.value;
|
||||||
} else {
|
} else {
|
||||||
// Coerce to string
|
|
||||||
const tempContext: NixStringContext = new Set();
|
const tempContext: NixStringContext = new Set();
|
||||||
const coerced = coerceToString(part, StringCoercionMode.Interpolation, false, tempContext);
|
const coerced = coerceToString(part, StringCoercionMode.Interpolation, false, tempContext);
|
||||||
|
|
||||||
@@ -132,19 +127,15 @@ export const concatStringsWithContext = (parts: NixValue[]): NixString | NixPath
|
|||||||
return mkPath(result);
|
return mkPath(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// String concatenation mode
|
|
||||||
// Note: firstIsPath is already false at this point, otherwise we would have
|
|
||||||
// returned in the path concatenation branch above
|
|
||||||
const context: NixStringContext = new Set();
|
const context: NixStringContext = new Set();
|
||||||
const strParts: string[] = [];
|
const strParts: string[] = [];
|
||||||
|
|
||||||
for (const part of parts) {
|
for (const part of forced) {
|
||||||
const forced = force(part);
|
if (isNixPath(part)) {
|
||||||
if (isNixPath(forced)) {
|
const str = coerceToString(part, StringCoercionMode.Interpolation, true, context);
|
||||||
const str = coerceToString(forced, StringCoercionMode.Interpolation, true, context);
|
|
||||||
strParts.push(str);
|
strParts.push(str);
|
||||||
} else {
|
} else {
|
||||||
const str = coerceToString(forced, StringCoercionMode.Interpolation, false, context);
|
const str = coerceToString(part, StringCoercionMode.Interpolation, false, context);
|
||||||
strParts.push(str);
|
strParts.push(str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,6 +165,10 @@ export const parseContextToInfoMap = (context: NixStringContext): Map<string, Pa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const info of result.values()) {
|
||||||
|
info.outputs.sort();
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -141,6 +141,12 @@ impl<Ctx: CodegenContext> Compile<Ctx> for usize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Ctx: CodegenContext> Compile<Ctx> for bool {
|
||||||
|
fn compile(&self, _ctx: &Ctx, buf: &mut CodeBuffer) {
|
||||||
|
let _ = write!(buf, "{self}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<Ctx: CodegenContext> Compile<Ctx> for Quoted<'_> {
|
impl<Ctx: CodegenContext> Compile<Ctx> for Quoted<'_> {
|
||||||
fn compile(&self, ctx: &Ctx, buf: &mut CodeBuffer) {
|
fn compile(&self, ctx: &Ctx, buf: &mut CodeBuffer) {
|
||||||
code!(buf, ctx; "\"" escaped(self.0) "\"")
|
code!(buf, ctx; "\"" escaped(self.0) "\"")
|
||||||
@@ -616,7 +622,7 @@ impl<Ctx: CodegenContext> Compile<Ctx> for ConcatStrings {
|
|||||||
"Nix.withContext(\"while evaluating a path segment\"," part.span() ",()=>(" part "))"
|
"Nix.withContext(\"while evaluating a path segment\"," part.span() ",()=>(" part "))"
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
"])"
|
"]," self.force_string ")"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ ir! {
|
|||||||
If { pub cond: ExprId, pub consq: ExprId, pub alter: ExprId },
|
If { pub cond: ExprId, pub consq: ExprId, pub alter: ExprId },
|
||||||
Call { pub func: ExprId, pub arg: ExprId },
|
Call { pub func: ExprId, pub arg: ExprId },
|
||||||
Assert { pub assertion: ExprId, pub expr: ExprId, pub assertion_raw: String },
|
Assert { pub assertion: ExprId, pub expr: ExprId, pub assertion_raw: String },
|
||||||
ConcatStrings { pub parts: Vec<ExprId> },
|
ConcatStrings { pub parts: Vec<ExprId>, pub force_string: bool },
|
||||||
Path { pub expr: ExprId },
|
Path { pub expr: ExprId },
|
||||||
Func { pub body: ExprId, pub param: Option<Param>, pub arg: ExprId, pub thunks: Vec<(ExprId, ExprId)> },
|
Func { pub body: ExprId, pub param: Option<Param>, pub arg: ExprId, pub thunks: Vec<(ExprId, ExprId)> },
|
||||||
TopLevel { pub body: ExprId, pub thunks: Vec<(ExprId, ExprId)> },
|
TopLevel { pub body: ExprId, pub thunks: Vec<(ExprId, ExprId)> },
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::Path {
|
|||||||
part
|
part
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx.new_expr(ConcatStrings { parts, span }.to_ir())
|
ctx.new_expr(ConcatStrings { parts, span, force_string: false }.to_ir())
|
||||||
};
|
};
|
||||||
Ok(ctx.new_expr(Path { expr, span }.to_ir()))
|
Ok(ctx.new_expr(Path { expr, span }.to_ir()))
|
||||||
}
|
}
|
||||||
@@ -166,7 +166,7 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::Str {
|
|||||||
Ok(if is_single_literal {
|
Ok(if is_single_literal {
|
||||||
parts.into_iter().next().unwrap()
|
parts.into_iter().next().unwrap()
|
||||||
} else {
|
} else {
|
||||||
ctx.new_expr(ConcatStrings { parts, span }.to_ir())
|
ctx.new_expr(ConcatStrings { parts, span, force_string: true }.to_ir())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -442,7 +442,7 @@ pub fn downgrade_attr(attr: ast::Attr, ctx: &mut impl DowngradeContext) -> Resul
|
|||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
Ok(Attr::Dynamic(
|
Ok(Attr::Dynamic(
|
||||||
ctx.new_expr(ConcatStrings { parts, span }.to_ir()),
|
ctx.new_expr(ConcatStrings { parts, span, force_string: true }.to_ir()),
|
||||||
span,
|
span,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user